summaryrefslogtreecommitdiff
path: root/RC9/qpid/cpp/src
diff options
context:
space:
mode:
Diffstat (limited to 'RC9/qpid/cpp/src')
-rw-r--r--RC9/qpid/cpp/src/Makefile.am715
-rw-r--r--RC9/qpid/cpp/src/MaxMethodBodySize.vcproj396
-rw-r--r--RC9/qpid/cpp/src/acl.mk34
-rw-r--r--RC9/qpid/cpp/src/broker.vcproj1280
-rw-r--r--RC9/qpid/cpp/src/client.vcproj574
-rw-r--r--RC9/qpid/cpp/src/cluster.mk75
-rw-r--r--RC9/qpid/cpp/src/common.vcproj1870
-rwxr-xr-xRC9/qpid/cpp/src/generate.sh67
-rw-r--r--RC9/qpid/cpp/src/posix/QpiddBroker.cpp168
-rwxr-xr-xRC9/qpid/cpp/src/prof39
-rw-r--r--RC9/qpid/cpp/src/protocol_gen.mak28
-rw-r--r--RC9/qpid/cpp/src/qmf.mk35
-rw-r--r--RC9/qpid/cpp/src/qmfc.mk65
-rw-r--r--RC9/qpid/cpp/src/qmfconsole.vcproj418
-rw-r--r--RC9/qpid/cpp/src/qpid.sln72
-rw-r--r--RC9/qpid/cpp/src/qpid/Address.cpp58
-rwxr-xr-xRC9/qpid/cpp/src/qpid/Address.h85
-rw-r--r--RC9/qpid/cpp/src/qpid/DataDir.cpp49
-rw-r--r--RC9/qpid/cpp/src/qpid/DataDir.h50
-rw-r--r--RC9/qpid/cpp/src/qpid/Exception.cpp55
-rw-r--r--RC9/qpid/cpp/src/qpid/Exception.h93
-rw-r--r--RC9/qpid/cpp/src/qpid/InlineAllocator.h84
-rw-r--r--RC9/qpid/cpp/src/qpid/InlineVector.h68
-rw-r--r--RC9/qpid/cpp/src/qpid/Modules.cpp78
-rw-r--r--RC9/qpid/cpp/src/qpid/Modules.h43
-rw-r--r--RC9/qpid/cpp/src/qpid/Msg.h61
-rw-r--r--RC9/qpid/cpp/src/qpid/Options.cpp468
-rw-r--r--RC9/qpid/cpp/src/qpid/Options.h257
-rw-r--r--RC9/qpid/cpp/src/qpid/Plugin.cpp80
-rw-r--r--RC9/qpid/cpp/src/qpid/Plugin.h118
-rw-r--r--RC9/qpid/cpp/src/qpid/RangeSet.h330
-rw-r--r--RC9/qpid/cpp/src/qpid/RefCounted.h59
-rw-r--r--RC9/qpid/cpp/src/qpid/RefCountedBuffer.cpp53
-rw-r--r--RC9/qpid/cpp/src/qpid/RefCountedBuffer.h89
-rw-r--r--RC9/qpid/cpp/src/qpid/Serializer.h197
-rw-r--r--RC9/qpid/cpp/src/qpid/SessionId.cpp47
-rw-r--r--RC9/qpid/cpp/src/qpid/SessionId.h59
-rw-r--r--RC9/qpid/cpp/src/qpid/SessionState.cpp278
-rw-r--r--RC9/qpid/cpp/src/qpid/SessionState.h219
-rw-r--r--RC9/qpid/cpp/src/qpid/SharedObject.h55
-rw-r--r--RC9/qpid/cpp/src/qpid/StringUtils.cpp50
-rw-r--r--RC9/qpid/cpp/src/qpid/StringUtils.h43
-rw-r--r--RC9/qpid/cpp/src/qpid/Url.cpp212
-rw-r--r--RC9/qpid/cpp/src/qpid/Url.h92
-rwxr-xr-xRC9/qpid/cpp/src/qpid/Version.h44
-rw-r--r--RC9/qpid/cpp/src/qpid/acl/Acl.cpp164
-rw-r--r--RC9/qpid/cpp/src/qpid/acl/Acl.h85
-rw-r--r--RC9/qpid/cpp/src/qpid/acl/AclData.cpp162
-rw-r--r--RC9/qpid/cpp/src/qpid/acl/AclData.h73
-rw-r--r--RC9/qpid/cpp/src/qpid/acl/AclPlugin.cpp101
-rw-r--r--RC9/qpid/cpp/src/qpid/acl/AclReader.cpp511
-rw-r--r--RC9/qpid/cpp/src/qpid/acl/AclReader.h117
-rw-r--r--RC9/qpid/cpp/src/qpid/acl/management-schema.xml44
-rw-r--r--RC9/qpid/cpp/src/qpid/agent/ManagementAgent.h162
-rw-r--r--RC9/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp906
-rw-r--r--RC9/qpid/cpp/src/qpid/agent/ManagementAgentImpl.h237
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/Array.cpp34
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/Array.h124
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/Body.h55
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/Codec.h213
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/Command.h62
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/CommmandPacker.h60
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/Connection.cpp138
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/Connection.h76
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/Control.h70
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/Decimal.h51
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/Exception.h96
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/FrameHeader.cpp50
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/FrameHeader.h90
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/Header.cpp34
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/Header.h53
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/Holder.h103
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/Map.cpp66
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/Map.h188
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/Packer.h195
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/SerializableString.h62
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/SessionHandler.cpp316
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/SessionHandler.h114
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/Struct.h60
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/Struct32.cpp36
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/Struct32.h64
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/Unit.cpp65
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/Unit.h82
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/UnitHandler.h35
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/UnknownStruct.cpp34
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/UnknownStruct.h55
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/UnknownType.cpp56
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/UnknownType.h87
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/apply.h86
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/built_in_types.h171
-rw-r--r--RC9/qpid/cpp/src/qpid/amqp_0_10/complex_types.cpp84
-rw-r--r--RC9/qpid/cpp/src/qpid/assert.cpp45
-rw-r--r--RC9/qpid/cpp/src/qpid/assert.h38
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/AclModule.h257
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/Bridge.cpp294
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/Bridge.h105
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/Broker.cpp450
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/Broker.h229
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/BrokerSingleton.cpp36
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/BrokerSingleton.h52
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/Connection.cpp271
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/Connection.h127
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/ConnectionFactory.cpp56
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/ConnectionFactory.h50
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/ConnectionHandler.cpp222
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/ConnectionHandler.h95
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/ConnectionState.h100
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/ConnectionToken.h40
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/Consumer.h53
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/Daemon.cpp212
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/Daemon.h82
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/Deliverable.h44
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/DeliverableMessage.cpp43
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/DeliverableMessage.h45
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/DeliveryAdapter.h53
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/DeliveryId.h35
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/DeliveryRecord.cpp214
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/DeliveryRecord.h141
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/DirectExchange.cpp190
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/DirectExchange.h65
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/DtxAck.cpp59
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/DtxAck.h48
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/DtxBuffer.cpp83
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/DtxBuffer.h56
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/DtxManager.cpp171
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/DtxManager.h74
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/DtxTimeout.cpp35
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/DtxTimeout.h48
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/DtxWorkRecord.cpp177
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/DtxWorkRecord.h79
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/Exchange.cpp270
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/Exchange.h178
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/ExchangeRegistry.cpp109
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/ExchangeRegistry.h90
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/FanOutExchange.cpp148
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/FanOutExchange.h65
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/HandlerImpl.h53
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/HeadersExchange.cpp226
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/HeadersExchange.h88
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/IncompleteMessageList.cpp81
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/IncompleteMessageList.h57
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/Link.cpp398
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/Link.h136
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/LinkRegistry.cpp252
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/LinkRegistry.h123
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/Message.cpp369
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/Message.h185
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/MessageAdapter.cpp70
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/MessageAdapter.h58
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/MessageBuilder.cpp128
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/MessageBuilder.h57
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/MessageStore.h199
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/MessageStoreModule.cpp174
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/MessageStoreModule.h85
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/NameGenerator.cpp32
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/NameGenerator.h39
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/NullMessageStore.cpp166
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/NullMessageStore.h88
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/OwnershipToken.h38
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/Persistable.h63
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/PersistableConfig.h45
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/PersistableExchange.h45
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/PersistableMessage.cpp143
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/PersistableMessage.h116
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/PersistableQueue.h87
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/Queue.cpp900
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/Queue.h287
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/QueueBindings.cpp46
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/QueueBindings.h61
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/QueueCleaner.cpp52
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/QueueCleaner.h57
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/QueueListeners.cpp73
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/QueueListeners.h68
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/QueuePolicy.cpp297
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/QueuePolicy.h109
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/QueueRegistry.cpp107
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/QueueRegistry.h134
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/QueuedMessage.h46
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/RateTracker.cpp51
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/RateTracker.h57
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/RecoverableConfig.h45
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/RecoverableExchange.h50
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/RecoverableMessage.h58
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/RecoverableQueue.h59
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/RecoverableTransaction.h49
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/RecoveredDequeue.cpp40
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/RecoveredDequeue.h57
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/RecoveredEnqueue.cpp40
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/RecoveredEnqueue.h58
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/RecoveryManager.h61
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/RecoveryManagerImpl.cpp253
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/RecoveryManagerImpl.h59
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/SaslAuthenticator.cpp337
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/SaslAuthenticator.h55
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/SemanticState.cpp669
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/SemanticState.h232
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/SessionAdapter.cpp749
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/SessionAdapter.h260
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/SessionContext.h52
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/SessionHandler.cpp101
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/SessionHandler.h81
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/SessionManager.cpp104
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/SessionManager.h87
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/SessionState.cpp271
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/SessionState.h144
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/SignalHandler.cpp48
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/SignalHandler.h47
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/System.cpp82
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/System.h49
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/Timer.cpp104
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/Timer.h79
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/TopicExchange.cpp313
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/TopicExchange.h110
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/TransactionalStore.h60
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/TxAccept.cpp99
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/TxAccept.h83
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/TxBuffer.cpp80
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/TxBuffer.h118
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/TxOp.h46
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/TxOpVisitor.h100
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/TxPublish.cpp80
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/TxPublish.h89
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/Vhost.cpp48
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/Vhost.h49
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/posix/BrokerDefaults.cpp30
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/windows/BrokerDefaults.cpp30
-rw-r--r--RC9/qpid/cpp/src/qpid/broker/windows/SaslAuthenticator.cpp175
-rw-r--r--RC9/qpid/cpp/src/qpid/client/AckMode.h53
-rw-r--r--RC9/qpid/cpp/src/qpid/client/AsyncSession.h38
-rw-r--r--RC9/qpid/cpp/src/qpid/client/Bounds.cpp71
-rw-r--r--RC9/qpid/cpp/src/qpid/client/Bounds.h49
-rw-r--r--RC9/qpid/cpp/src/qpid/client/ChainableFrameHandler.h47
-rw-r--r--RC9/qpid/cpp/src/qpid/client/Completion.h71
-rw-r--r--RC9/qpid/cpp/src/qpid/client/Connection.cpp145
-rw-r--r--RC9/qpid/cpp/src/qpid/client/Connection.h185
-rw-r--r--RC9/qpid/cpp/src/qpid/client/ConnectionAccess.h41
-rw-r--r--RC9/qpid/cpp/src/qpid/client/ConnectionHandler.cpp226
-rw-r--r--RC9/qpid/cpp/src/qpid/client/ConnectionHandler.h116
-rw-r--r--RC9/qpid/cpp/src/qpid/client/ConnectionImpl.cpp201
-rw-r--r--RC9/qpid/cpp/src/qpid/client/ConnectionImpl.h99
-rw-r--r--RC9/qpid/cpp/src/qpid/client/ConnectionSettings.cpp54
-rw-r--r--RC9/qpid/cpp/src/qpid/client/ConnectionSettings.h118
-rw-r--r--RC9/qpid/cpp/src/qpid/client/Connector.cpp413
-rw-r--r--RC9/qpid/cpp/src/qpid/client/Connector.h73
-rw-r--r--RC9/qpid/cpp/src/qpid/client/Demux.cpp132
-rw-r--r--RC9/qpid/cpp/src/qpid/client/Demux.h102
-rw-r--r--RC9/qpid/cpp/src/qpid/client/Dispatcher.cpp144
-rw-r--r--RC9/qpid/cpp/src/qpid/client/Dispatcher.h82
-rw-r--r--RC9/qpid/cpp/src/qpid/client/Execution.h53
-rw-r--r--RC9/qpid/cpp/src/qpid/client/FailoverListener.cpp115
-rw-r--r--RC9/qpid/cpp/src/qpid/client/FailoverListener.h59
-rw-r--r--RC9/qpid/cpp/src/qpid/client/FailoverManager.cpp119
-rw-r--r--RC9/qpid/cpp/src/qpid/client/FailoverManager.h134
-rw-r--r--RC9/qpid/cpp/src/qpid/client/FlowControl.h75
-rw-r--r--RC9/qpid/cpp/src/qpid/client/Future.cpp45
-rw-r--r--RC9/qpid/cpp/src/qpid/client/Future.h64
-rw-r--r--RC9/qpid/cpp/src/qpid/client/FutureCompletion.cpp48
-rw-r--r--RC9/qpid/cpp/src/qpid/client/FutureCompletion.h49
-rw-r--r--RC9/qpid/cpp/src/qpid/client/FutureResult.cpp43
-rw-r--r--RC9/qpid/cpp/src/qpid/client/FutureResult.h47
-rw-r--r--RC9/qpid/cpp/src/qpid/client/Handle.h61
-rw-r--r--RC9/qpid/cpp/src/qpid/client/HandleAccess.h41
-rw-r--r--RC9/qpid/cpp/src/qpid/client/HandlePrivate.h61
-rw-r--r--RC9/qpid/cpp/src/qpid/client/LoadPlugins.cpp49
-rw-r--r--RC9/qpid/cpp/src/qpid/client/LocalQueue.cpp77
-rw-r--r--RC9/qpid/cpp/src/qpid/client/LocalQueue.h115
-rw-r--r--RC9/qpid/cpp/src/qpid/client/Message.cpp71
-rw-r--r--RC9/qpid/cpp/src/qpid/client/Message.h151
-rw-r--r--RC9/qpid/cpp/src/qpid/client/MessageListener.cpp24
-rw-r--r--RC9/qpid/cpp/src/qpid/client/MessageListener.h100
-rw-r--r--RC9/qpid/cpp/src/qpid/client/MessageReplayTracker.cpp80
-rw-r--r--RC9/qpid/cpp/src/qpid/client/MessageReplayTracker.h73
-rw-r--r--RC9/qpid/cpp/src/qpid/client/QueueOptions.cpp116
-rw-r--r--RC9/qpid/cpp/src/qpid/client/QueueOptions.h104
-rw-r--r--RC9/qpid/cpp/src/qpid/client/RdmaConnector.cpp428
-rw-r--r--RC9/qpid/cpp/src/qpid/client/Results.cpp76
-rw-r--r--RC9/qpid/cpp/src/qpid/client/Results.h56
-rw-r--r--RC9/qpid/cpp/src/qpid/client/Session.h39
-rw-r--r--RC9/qpid/cpp/src/qpid/client/SessionBase_0_10.cpp77
-rw-r--r--RC9/qpid/cpp/src/qpid/client/SessionBase_0_10.h118
-rw-r--r--RC9/qpid/cpp/src/qpid/client/SessionBase_0_10Access.h42
-rw-r--r--RC9/qpid/cpp/src/qpid/client/SessionImpl.cpp695
-rw-r--r--RC9/qpid/cpp/src/qpid/client/SessionImpl.h219
-rw-r--r--RC9/qpid/cpp/src/qpid/client/SslConnector.cpp399
-rw-r--r--RC9/qpid/cpp/src/qpid/client/StateManager.cpp68
-rw-r--r--RC9/qpid/cpp/src/qpid/client/StateManager.h47
-rw-r--r--RC9/qpid/cpp/src/qpid/client/Subscription.cpp50
-rw-r--r--RC9/qpid/cpp/src/qpid/client/Subscription.h113
-rw-r--r--RC9/qpid/cpp/src/qpid/client/SubscriptionImpl.cpp149
-rw-r--r--RC9/qpid/cpp/src/qpid/client/SubscriptionImpl.h109
-rw-r--r--RC9/qpid/cpp/src/qpid/client/SubscriptionManager.cpp140
-rw-r--r--RC9/qpid/cpp/src/qpid/client/SubscriptionManager.h293
-rw-r--r--RC9/qpid/cpp/src/qpid/client/SubscriptionSettings.h92
-rw-r--r--RC9/qpid/cpp/src/qpid/client/TypedResult.h65
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/Cluster.cpp548
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/Cluster.h230
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/ClusterLeaveException.h35
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/ClusterMap.cpp173
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/ClusterMap.h99
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/ClusterPlugin.cpp106
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/Connection.cpp370
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/Connection.h177
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/ConnectionCodec.cpp82
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/ConnectionCodec.h80
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/ConnectionMap.h90
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/Cpg.cpp197
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/Cpg.h169
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/Dispatchable.h52
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/DumpClient.cpp369
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/DumpClient.h101
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/Event.cpp89
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/Event.h87
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/FailoverExchange.cpp99
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/FailoverExchange.h68
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/Multicaster.cpp84
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/Multicaster.h71
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/NoOpConnectionOutputHandler.h47
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/OutputInterceptor.cpp121
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/OutputInterceptor.h75
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/ProxyInputHandler.h57
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/Quorum.h32
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/Quorum_cman.cpp49
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/Quorum_cman.h50
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/Quorum_null.h37
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/WriteEstimate.cpp64
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/WriteEstimate.h69
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/management-schema.xml57
-rw-r--r--RC9/qpid/cpp/src/qpid/cluster/types.h84
-rw-r--r--RC9/qpid/cpp/src/qpid/console/Agent.cpp30
-rw-r--r--RC9/qpid/cpp/src/qpid/console/Agent.h57
-rw-r--r--RC9/qpid/cpp/src/qpid/console/Broker.cpp300
-rw-r--r--RC9/qpid/cpp/src/qpid/console/Broker.h130
-rw-r--r--RC9/qpid/cpp/src/qpid/console/ClassKey.cpp104
-rw-r--r--RC9/qpid/cpp/src/qpid/console/ClassKey.h65
-rw-r--r--RC9/qpid/cpp/src/qpid/console/ConsoleListener.h96
-rw-r--r--RC9/qpid/cpp/src/qpid/console/Event.cpp205
-rw-r--r--RC9/qpid/cpp/src/qpid/console/Event.h83
-rw-r--r--RC9/qpid/cpp/src/qpid/console/Object.cpp383
-rw-r--r--RC9/qpid/cpp/src/qpid/console/Object.h119
-rw-r--r--RC9/qpid/cpp/src/qpid/console/ObjectId.cpp52
-rw-r--r--RC9/qpid/cpp/src/qpid/console/ObjectId.h60
-rw-r--r--RC9/qpid/cpp/src/qpid/console/Package.cpp41
-rw-r--r--RC9/qpid/cpp/src/qpid/console/Package.h76
-rw-r--r--RC9/qpid/cpp/src/qpid/console/Schema.cpp155
-rw-r--r--RC9/qpid/cpp/src/qpid/console/Schema.h105
-rw-r--r--RC9/qpid/cpp/src/qpid/console/SequenceManager.cpp48
-rw-r--r--RC9/qpid/cpp/src/qpid/console/SequenceManager.h53
-rw-r--r--RC9/qpid/cpp/src/qpid/console/SessionManager.cpp462
-rw-r--r--RC9/qpid/cpp/src/qpid/console/SessionManager.h199
-rw-r--r--RC9/qpid/cpp/src/qpid/console/Value.cpp168
-rw-r--r--RC9/qpid/cpp/src/qpid/console/Value.h207
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/AMQBody.cpp64
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/AMQBody.h78
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/AMQCommandControlBody.h70
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/AMQContentBody.cpp44
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/AMQContentBody.h53
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/AMQDataBlock.h42
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/AMQFrame.cpp124
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/AMQFrame.h128
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/AMQHeaderBody.cpp63
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/AMQHeaderBody.h108
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/AMQHeartbeatBody.cpp29
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/AMQHeartbeatBody.h46
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/AMQMethodBody.cpp28
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/AMQMethodBody.h72
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/AMQP_HighestVersion.h40
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/AccumulatedAck.cpp164
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/AccumulatedAck.h76
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/Array.cpp129
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/Array.h96
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/Blob.cpp31
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/Blob.h197
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/BodyHandler.cpp55
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/BodyHandler.h56
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/BodyHolder.cpp76
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/BodyHolder.h88
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/Buffer.cpp319
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/Buffer.h135
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/ChannelHandler.h53
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/Endian.cpp52
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/Endian.h46
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/FieldTable.cpp240
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/FieldTable.h120
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/FieldValue.cpp180
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/FieldValue.h320
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/FrameDecoder.cpp68
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/FrameDecoder.h44
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/FrameDefaultVisitor.h60
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/FrameHandler.h33
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/FrameSet.cpp90
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/FrameSet.h107
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/Handler.h101
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/HeaderProperties.h44
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/InitiationHandler.cpp24
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/InitiationHandler.h41
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/InputHandler.h41
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/Invoker.h86
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/MethodContent.h40
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/ModelMethod.h49
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/OutputHandler.h42
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/ProtocolInitiation.cpp66
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/ProtocolInitiation.h58
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/ProtocolVersion.cpp44
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/ProtocolVersion.h57
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/Proxy.cpp42
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/Proxy.h54
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/SendContent.cpp69
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/SendContent.h55
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/SequenceNumber.cpp110
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/SequenceNumber.h75
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/SequenceNumberSet.cpp89
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/SequenceNumberSet.h68
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/SequenceSet.cpp100
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/SequenceSet.h68
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/StructHelper.h56
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/TemplateVisitor.h89
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/TransferContent.cpp102
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/TransferContent.h63
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/TypeFilter.h51
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/Uuid.cpp61
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/Uuid.h88
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/Visitor.h92
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/amqp_framing.h32
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/amqp_types.h63
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/amqp_types_full.h38
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/frame_functors.h116
-rw-r--r--RC9/qpid/cpp/src/qpid/framing/variant.h91
-rw-r--r--RC9/qpid/cpp/src/qpid/log/Helpers.h79
-rw-r--r--RC9/qpid/cpp/src/qpid/log/Logger.cpp168
-rw-r--r--RC9/qpid/cpp/src/qpid/log/Logger.h113
-rw-r--r--RC9/qpid/cpp/src/qpid/log/Options.cpp107
-rw-r--r--RC9/qpid/cpp/src/qpid/log/Options.h49
-rw-r--r--RC9/qpid/cpp/src/qpid/log/OstreamOutput.cpp41
-rw-r--r--RC9/qpid/cpp/src/qpid/log/OstreamOutput.h41
-rw-r--r--RC9/qpid/cpp/src/qpid/log/Selector.cpp67
-rw-r--r--RC9/qpid/cpp/src/qpid/log/Selector.h70
-rw-r--r--RC9/qpid/cpp/src/qpid/log/SinkOptions.h64
-rw-r--r--RC9/qpid/cpp/src/qpid/log/Statement.cpp83
-rw-r--r--RC9/qpid/cpp/src/qpid/log/Statement.h121
-rw-r--r--RC9/qpid/cpp/src/qpid/log/posix/SinkOptions.cpp211
-rw-r--r--RC9/qpid/cpp/src/qpid/log/posix/SinkOptions.h64
-rw-r--r--RC9/qpid/cpp/src/qpid/log/windows/SinkOptions.cpp148
-rw-r--r--RC9/qpid/cpp/src/qpid/log/windows/SinkOptions.h54
-rw-r--r--RC9/qpid/cpp/src/qpid/management/Args.h44
-rw-r--r--RC9/qpid/cpp/src/qpid/management/Manageable.cpp48
-rw-r--r--RC9/qpid/cpp/src/qpid/management/Manageable.h71
-rw-r--r--RC9/qpid/cpp/src/qpid/management/ManagementBroker.cpp1138
-rw-r--r--RC9/qpid/cpp/src/qpid/management/ManagementBroker.h235
-rw-r--r--RC9/qpid/cpp/src/qpid/management/ManagementEvent.h49
-rw-r--r--RC9/qpid/cpp/src/qpid/management/ManagementExchange.cpp72
-rw-r--r--RC9/qpid/cpp/src/qpid/management/ManagementExchange.h62
-rw-r--r--RC9/qpid/cpp/src/qpid/management/ManagementObject.cpp183
-rw-r--r--RC9/qpid/cpp/src/qpid/management/ManagementObject.h188
-rw-r--r--RC9/qpid/cpp/src/qpid/memory.h32
-rw-r--r--RC9/qpid/cpp/src/qpid/pointer_to_other.h62
-rw-r--r--RC9/qpid/cpp/src/qpid/ptr_map.h57
-rw-r--r--RC9/qpid/cpp/src/qpid/shared_ptr.h51
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/ActivityTimer.h106
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/AggregateOutput.cpp73
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/AggregateOutput.h65
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/AsynchIO.h152
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/AsynchIOHandler.cpp199
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/AsynchIOHandler.h79
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/AtomicCount.h52
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/AtomicValue.h34
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/AtomicValue_gcc.h68
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/AtomicValue_mutex.h83
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/BlockingQueue.h125
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/Condition.h33
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/ConnectionCodec.h78
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/ConnectionInputHandler.h44
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/ConnectionInputHandlerFactory.h54
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/ConnectionOutputHandler.h43
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/ConnectionOutputHandlerPtr.h55
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/CopyOnWriteArray.h126
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/DeletionManager.h138
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/DispatchHandle.cpp409
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/DispatchHandle.h146
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/Dispatcher.cpp59
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/Dispatcher.h43
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/ExceptionHolder.h75
-rwxr-xr-xRC9/qpid/cpp/src/qpid/sys/FileSysDir.h62
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/Fork.h24
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/IOHandle.h59
-rwxr-xr-xRC9/qpid/cpp/src/qpid/sys/IntegerTypes.h31
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/LockFile.h80
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/LockPtr.h89
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/Monitor.h49
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/Mutex.h91
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/OutputControl.h42
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/OutputTask.h48
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/PollableCondition.h28
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/PollableQueue.h152
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/Poller.h109
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/ProtocolFactory.h58
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/RdmaIOPlugin.cpp356
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/Runnable.cpp32
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/Runnable.h50
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/ScopedIncrement.h67
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/Semaphore.h67
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/Shlib.cpp38
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/Shlib.h75
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/ShutdownHandler.h37
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/Socket.h110
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/SslPlugin.cpp184
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/StateMonitor.h78
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/StrError.h35
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/SystemInfo.h79
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/TCPIOPlugin.cpp146
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/Thread.h62
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/Time.h168
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/TimeoutHandler.h39
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/Waitable.h114
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/apr/APRBase.cpp89
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/apr/APRBase.h74
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/apr/APRPool.cpp41
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/apr/APRPool.h50
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/apr/Condition.h84
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/apr/Mutex.h124
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/apr/Shlib.cpp49
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/apr/Socket.cpp114
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/apr/Thread.cpp34
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/apr/Thread.h106
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/apr/Time.cpp36
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/epoll/EpollPoller.cpp371
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp595
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/posix/Condition.h86
-rwxr-xr-xRC9/qpid/cpp/src/qpid/sys/posix/FileSysDir.cpp54
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/posix/Fork.cpp127
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/posix/Fork.h82
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/posix/IOHandle.cpp42
-rwxr-xr-xRC9/qpid/cpp/src/qpid/sys/posix/IntegerTypes.h26
-rwxr-xr-xRC9/qpid/cpp/src/qpid/sys/posix/LockFile.cpp89
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/posix/Mutex.cpp46
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/posix/Mutex.h158
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/posix/PollableCondition.cpp96
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/posix/PollableCondition.h56
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/posix/PrivatePosix.h52
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/posix/Shlib.cpp59
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/posix/Socket.cpp264
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/posix/StrError.cpp41
-rwxr-xr-xRC9/qpid/cpp/src/qpid/sys/posix/SystemInfo.cpp109
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/posix/Thread.cpp75
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/posix/Time.cpp110
-rwxr-xr-xRC9/qpid/cpp/src/qpid/sys/posix/Time.h34
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/posix/check.h49
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/rdma/RdmaClient.cpp207
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/rdma/RdmaIO.cpp617
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/rdma/RdmaIO.h222
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/rdma/RdmaServer.cpp167
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/rdma/rdma_exception.h65
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/rdma/rdma_factories.cpp64
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/rdma/rdma_factories.h69
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/rdma/rdma_wrap.cpp183
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/rdma/rdma_wrap.h498
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/solaris/ECFPoller.cpp301
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/ssl/SslHandler.cpp181
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/ssl/SslHandler.h76
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/ssl/SslIo.cpp433
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/ssl/SslIo.h167
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/ssl/SslSocket.cpp279
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/ssl/SslSocket.h117
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/ssl/check.cpp72
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/ssl/check.h53
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/ssl/util.cpp118
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/ssl/util.h50
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/uuid.h28
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/windows/AsynchIO.cpp741
-rwxr-xr-xRC9/qpid/cpp/src/qpid/sys/windows/AsynchIoResult.h185
-rwxr-xr-xRC9/qpid/cpp/src/qpid/sys/windows/Condition.h80
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/windows/FileSysDir.cpp53
-rwxr-xr-xRC9/qpid/cpp/src/qpid/sys/windows/IOHandle.cpp42
-rwxr-xr-xRC9/qpid/cpp/src/qpid/sys/windows/IntegerTypes.h40
-rwxr-xr-xRC9/qpid/cpp/src/qpid/sys/windows/IoHandlePrivate.h52
-rwxr-xr-xRC9/qpid/cpp/src/qpid/sys/windows/IocpDispatcher.cpp54
-rwxr-xr-xRC9/qpid/cpp/src/qpid/sys/windows/IocpPoller.cpp176
-rwxr-xr-xRC9/qpid/cpp/src/qpid/sys/windows/LockFile.cpp83
-rwxr-xr-xRC9/qpid/cpp/src/qpid/sys/windows/Mutex.h188
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/windows/Shlib.cpp53
-rwxr-xr-xRC9/qpid/cpp/src/qpid/sys/windows/Socket.cpp329
-rwxr-xr-xRC9/qpid/cpp/src/qpid/sys/windows/StrError.cpp47
-rwxr-xr-xRC9/qpid/cpp/src/qpid/sys/windows/SystemInfo.cpp160
-rwxr-xr-xRC9/qpid/cpp/src/qpid/sys/windows/Thread.cpp88
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/windows/Time.cpp90
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/windows/Time.h36
-rwxr-xr-xRC9/qpid/cpp/src/qpid/sys/windows/check.h48
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/windows/uuid.cpp54
-rw-r--r--RC9/qpid/cpp/src/qpid/sys/windows/uuid.h41
-rw-r--r--RC9/qpid/cpp/src/qpid/xml/XmlBinding.h37
-rw-r--r--RC9/qpid/cpp/src/qpid/xml/XmlExchange.cpp263
-rw-r--r--RC9/qpid/cpp/src/qpid/xml/XmlExchange.h88
-rw-r--r--RC9/qpid/cpp/src/qpid/xml/XmlExchangePlugin.cpp67
-rw-r--r--RC9/qpid/cpp/src/qpidd.cpp83
-rw-r--r--RC9/qpid/cpp/src/qpidd.h70
-rw-r--r--RC9/qpid/cpp/src/ssl.mk64
-rw-r--r--RC9/qpid/cpp/src/tests/.valgrind.supp203
-rw-r--r--RC9/qpid/cpp/src/tests/AccumulatedAckTest.cpp232
-rw-r--r--RC9/qpid/cpp/src/tests/Array.cpp79
-rw-r--r--RC9/qpid/cpp/src/tests/AsyncCompletion.cpp100
-rw-r--r--RC9/qpid/cpp/src/tests/AtomicValue.cpp49
-rw-r--r--RC9/qpid/cpp/src/tests/BasicP2PTest.cpp66
-rw-r--r--RC9/qpid/cpp/src/tests/BasicP2PTest.h46
-rw-r--r--RC9/qpid/cpp/src/tests/BasicPubSubTest.cpp121
-rw-r--r--RC9/qpid/cpp/src/tests/BasicPubSubTest.h51
-rw-r--r--RC9/qpid/cpp/src/tests/Blob.cpp128
-rw-r--r--RC9/qpid/cpp/src/tests/BrokerFixture.h130
-rw-r--r--RC9/qpid/cpp/src/tests/ClientSessionTest.cpp452
-rw-r--r--RC9/qpid/cpp/src/tests/ConnectionOptions.h54
-rw-r--r--RC9/qpid/cpp/src/tests/ConsoleTest.cpp43
-rw-r--r--RC9/qpid/cpp/src/tests/DeliveryRecordTest.cpp62
-rw-r--r--RC9/qpid/cpp/src/tests/DispatcherTest.cpp128
-rw-r--r--RC9/qpid/cpp/src/tests/DtxWorkRecordTest.cpp189
-rw-r--r--RC9/qpid/cpp/src/tests/ExchangeTest.cpp284
-rw-r--r--RC9/qpid/cpp/src/tests/FieldTable.cpp178
-rw-r--r--RC9/qpid/cpp/src/tests/FieldValue.cpp90
-rw-r--r--RC9/qpid/cpp/src/tests/ForkedBroker.h122
-rw-r--r--RC9/qpid/cpp/src/tests/Frame.cpp80
-rw-r--r--RC9/qpid/cpp/src/tests/FramingTest.cpp151
-rw-r--r--RC9/qpid/cpp/src/tests/HeaderTest.cpp110
-rw-r--r--RC9/qpid/cpp/src/tests/HeadersExchangeTest.cpp115
-rw-r--r--RC9/qpid/cpp/src/tests/IncompleteMessageList.cpp128
-rw-r--r--RC9/qpid/cpp/src/tests/InlineAllocator.cpp63
-rw-r--r--RC9/qpid/cpp/src/tests/InlineVector.cpp119
-rw-r--r--RC9/qpid/cpp/src/tests/Makefile.am245
-rw-r--r--RC9/qpid/cpp/src/tests/ManagementTest.cpp85
-rw-r--r--RC9/qpid/cpp/src/tests/MessageBuilderTest.cpp224
-rw-r--r--RC9/qpid/cpp/src/tests/MessageReplayTracker.cpp99
-rw-r--r--RC9/qpid/cpp/src/tests/MessageTest.cpp90
-rw-r--r--RC9/qpid/cpp/src/tests/MessageUtils.h55
-rw-r--r--RC9/qpid/cpp/src/tests/PollerTest.cpp164
-rw-r--r--RC9/qpid/cpp/src/tests/QueueOptionsTest.cpp98
-rw-r--r--RC9/qpid/cpp/src/tests/QueuePolicyTest.cpp274
-rw-r--r--RC9/qpid/cpp/src/tests/QueueRegistryTest.cpp94
-rw-r--r--RC9/qpid/cpp/src/tests/QueueTest.cpp501
-rw-r--r--RC9/qpid/cpp/src/tests/README54
-rw-r--r--RC9/qpid/cpp/src/tests/RangeSet.cpp141
-rw-r--r--RC9/qpid/cpp/src/tests/RefCounted.cpp50
-rw-r--r--RC9/qpid/cpp/src/tests/SequenceNumberTest.cpp205
-rw-r--r--RC9/qpid/cpp/src/tests/SequenceSet.cpp140
-rw-r--r--RC9/qpid/cpp/src/tests/SessionState.cpp300
-rw-r--r--RC9/qpid/cpp/src/tests/Shlib.cpp60
-rw-r--r--RC9/qpid/cpp/src/tests/SimpleTestCaseBase.cpp87
-rw-r--r--RC9/qpid/cpp/src/tests/SimpleTestCaseBase.h89
-rw-r--r--RC9/qpid/cpp/src/tests/SocketProxy.h143
-rw-r--r--RC9/qpid/cpp/src/tests/StringUtils.cpp77
-rw-r--r--RC9/qpid/cpp/src/tests/TestCase.h64
-rw-r--r--RC9/qpid/cpp/src/tests/TestMessageStore.h58
-rw-r--r--RC9/qpid/cpp/src/tests/TestOptions.h79
-rw-r--r--RC9/qpid/cpp/src/tests/TimerTest.cpp120
-rw-r--r--RC9/qpid/cpp/src/tests/TopicExchangeTest.cpp167
-rw-r--r--RC9/qpid/cpp/src/tests/TxBufferTest.cpp176
-rw-r--r--RC9/qpid/cpp/src/tests/TxMocks.h229
-rw-r--r--RC9/qpid/cpp/src/tests/TxPublishTest.cpp94
-rw-r--r--RC9/qpid/cpp/src/tests/Url.cpp67
-rw-r--r--RC9/qpid/cpp/src/tests/Uuid.cpp79
-rw-r--r--RC9/qpid/cpp/src/tests/XmlClientSessionTest.cpp221
-rwxr-xr-xRC9/qpid/cpp/src/tests/acl.py459
-rwxr-xr-xRC9/qpid/cpp/src/tests/ais_check56
-rw-r--r--RC9/qpid/cpp/src/tests/ais_test.cpp23
-rw-r--r--RC9/qpid/cpp/src/tests/allSegmentTypes.h128
-rw-r--r--RC9/qpid/cpp/src/tests/amqp_0_10/Map.cpp98
-rw-r--r--RC9/qpid/cpp/src/tests/amqp_0_10/ProxyTemplate.cpp49
-rw-r--r--RC9/qpid/cpp/src/tests/amqp_0_10/apply.cpp99
-rw-r--r--RC9/qpid/cpp/src/tests/amqp_0_10/handlers.cpp125
-rw-r--r--RC9/qpid/cpp/src/tests/amqp_0_10/serialize.cpp429
-rwxr-xr-xRC9/qpid/cpp/src/tests/benchmark95
-rw-r--r--RC9/qpid/cpp/src/tests/client_test.cpp149
-rw-r--r--RC9/qpid/cpp/src/tests/cluster.mk41
-rw-r--r--RC9/qpid/cpp/src/tests/cluster_test.cpp648
-rw-r--r--RC9/qpid/cpp/src/tests/config.null1
-rw-r--r--RC9/qpid/cpp/src/tests/consume.cpp119
-rw-r--r--RC9/qpid/cpp/src/tests/declare_queues.cpp69
-rw-r--r--RC9/qpid/cpp/src/tests/dlclose_noop.c30
-rw-r--r--RC9/qpid/cpp/src/tests/echotest.cpp150
-rw-r--r--RC9/qpid/cpp/src/tests/exception_test.cpp121
-rw-r--r--RC9/qpid/cpp/src/tests/failover_soak.cpp654
-rwxr-xr-xRC9/qpid/cpp/src/tests/fanout_perftest22
-rwxr-xr-xRC9/qpid/cpp/src/tests/federated_topic_test130
-rwxr-xr-xRC9/qpid/cpp/src/tests/federation.py505
-rw-r--r--RC9/qpid/cpp/src/tests/header_test.cpp59
-rwxr-xr-xRC9/qpid/cpp/src/tests/header_test.py86
-rw-r--r--RC9/qpid/cpp/src/tests/interop_runner.cpp251
-rw-r--r--RC9/qpid/cpp/src/tests/latencytest.cpp432
-rw-r--r--RC9/qpid/cpp/src/tests/logging.cpp366
-rwxr-xr-xRC9/qpid/cpp/src/tests/multiq_perftest22
-rwxr-xr-xRC9/qpid/cpp/src/tests/perfdist87
-rw-r--r--RC9/qpid/cpp/src/tests/perftest.cpp701
-rw-r--r--RC9/qpid/cpp/src/tests/policy.acl1
-rw-r--r--RC9/qpid/cpp/src/tests/publish.cpp128
-rwxr-xr-xRC9/qpid/cpp/src/tests/python_tests39
-rwxr-xr-xRC9/qpid/cpp/src/tests/quick_perftest22
-rwxr-xr-xRC9/qpid/cpp/src/tests/quick_topictest30
-rwxr-xr-xRC9/qpid/cpp/src/tests/quick_txtest22
-rw-r--r--RC9/qpid/cpp/src/tests/receiver.cpp129
-rw-r--r--RC9/qpid/cpp/src/tests/replaying_sender.cpp131
-rwxr-xr-xRC9/qpid/cpp/src/tests/restart_cluster38
-rw-r--r--RC9/qpid/cpp/src/tests/resuming_receiver.cpp163
-rwxr-xr-xRC9/qpid/cpp/src/tests/run-unit-tests48
-rwxr-xr-xRC9/qpid/cpp/src/tests/run_acl_tests64
-rwxr-xr-xRC9/qpid/cpp/src/tests/run_failover_soak56
-rwxr-xr-xRC9/qpid/cpp/src/tests/run_federation_tests52
-rwxr-xr-xRC9/qpid/cpp/src/tests/run_header_test37
-rwxr-xr-xRC9/qpid/cpp/src/tests/run_perftest28
-rwxr-xr-xRC9/qpid/cpp/src/tests/run_test78
-rw-r--r--RC9/qpid/cpp/src/tests/sender.cpp100
-rwxr-xr-xRC9/qpid/cpp/src/tests/shared_perftest22
-rw-r--r--RC9/qpid/cpp/src/tests/shlibtest.cpp28
-rw-r--r--RC9/qpid/cpp/src/tests/ssl.mk23
-rwxr-xr-xRC9/qpid/cpp/src/tests/ssl_test71
-rwxr-xr-xRC9/qpid/cpp/src/tests/start_broker24
-rwxr-xr-xRC9/qpid/cpp/src/tests/start_cluster46
-rwxr-xr-xRC9/qpid/cpp/src/tests/start_cluster_hosts70
-rwxr-xr-xRC9/qpid/cpp/src/tests/stop_broker41
-rwxr-xr-xRC9/qpid/cpp/src/tests/stop_cluster33
-rw-r--r--RC9/qpid/cpp/src/tests/test_tools.h94
-rw-r--r--RC9/qpid/cpp/src/tests/topic_listener.cpp202
-rwxr-xr-xRC9/qpid/cpp/src/tests/topic_perftest22
-rw-r--r--RC9/qpid/cpp/src/tests/topic_publisher.cpp224
-rwxr-xr-xRC9/qpid/cpp/src/tests/topictest61
-rw-r--r--RC9/qpid/cpp/src/tests/txjob.cpp95
-rw-r--r--RC9/qpid/cpp/src/tests/txshift.cpp185
-rw-r--r--RC9/qpid/cpp/src/tests/txtest.cpp329
-rw-r--r--RC9/qpid/cpp/src/tests/unit_test.cpp23
-rw-r--r--RC9/qpid/cpp/src/tests/unit_test.h86
-rw-r--r--RC9/qpid/cpp/src/tests/vg_check24
-rw-r--r--RC9/qpid/cpp/src/windows/QpiddBroker.cpp89
-rw-r--r--RC9/qpid/cpp/src/xml.mk28
727 files changed, 90284 insertions, 0 deletions
diff --git a/RC9/qpid/cpp/src/Makefile.am b/RC9/qpid/cpp/src/Makefile.am
new file mode 100644
index 0000000000..422d456fa5
--- /dev/null
+++ b/RC9/qpid/cpp/src/Makefile.am
@@ -0,0 +1,715 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+SUBDIRS = . tests
+
+# The Windows-only sources are not compiled using this Makefile, but
+# are listed here to ensure they're included in releases. They are built
+# using Visual Studio solutions/projects.
+windows_dist = \
+ qpid.sln \
+ broker.vcproj \
+ common.vcproj \
+ client.vcproj \
+ MaxMethodBodySize.vcproj \
+ qmfconsole.vcproj \
+ protocol_gen.mak \
+ qpid/log/windows/SinkOptions.cpp \
+ qpid/log/windows/SinkOptions.h \
+ qpid/sys/windows/check.h \
+ qpid/sys/windows/AsynchIO.cpp \
+ qpid/sys/windows/AsynchIoResult.h \
+ qpid/sys/windows/Condition.h \
+ qpid/sys/windows/FileSysDir.cpp \
+ qpid/sys/windows/IntegerTypes.h \
+ qpid/sys/windows/IocpDispatcher.cpp \
+ qpid/sys/windows/IocpPoller.cpp \
+ qpid/sys/windows/IOHandle.cpp \
+ qpid/sys/windows/IoHandlePrivate.h \
+ qpid/sys/windows/LockFile.cpp \
+ qpid/sys/windows/Mutex.h \
+ qpid/sys/windows/Shlib.cpp \
+ qpid/sys/windows/Socket.cpp \
+ qpid/sys/windows/StrError.cpp \
+ qpid/sys/windows/SystemInfo.cpp \
+ qpid/sys/windows/Thread.cpp \
+ qpid/sys/windows/Time.cpp \
+ qpid/sys/windows/Time.h \
+ qpid/sys/windows/uuid.cpp \
+ qpid/sys/windows/uuid.h \
+ windows/QpiddBroker.cpp \
+ qpid/broker/windows/BrokerDefaults.cpp \
+ qpid/broker/windows/SaslAuthenticator.cpp
+
+EXTRA_DIST= $(platform_dist) $(rgen_srcs) $(windows_dist)
+
+## Generated code
+
+# Note: generated soure and makefiles included in distribution so a
+# distribution can be built without code generation tools and XML
+# sources.
+
+# This phony target is needed by generated makefile fragments:
+force:
+
+if GENERATE
+
+# AMQP_FINAL_XML is defined in ../configure.ac
+amqp_0_10_xml=@AMQP_FINAL_XML@
+specs=$(amqp_0_10_xml) $(top_srcdir)/xml/cluster.xml
+
+# Ruby generator.
+rgen_dir=$(top_srcdir)/rubygen
+rgen_cmd=ruby -I $(rgen_dir) $(rgen_dir)/generate gen $(specs) all $(srcdir)/rubygen.mk
+
+$(rgen_srcs) $(srcdir)/rubygen.mk: rgen.timestamp
+rgen.timestamp: $(rgen_generator) $(specs)
+ $(rgen_cmd); touch $@
+$(rgen_generator):
+
+# Management generator.
+mgen_dir=$(top_srcdir)/managementgen
+mgen_cmd=$(mgen_dir)/qmf-gen -m $(srcdir)/managementgen.mk -q -o gen/qmf \
+ $(top_srcdir)/../specs/management-schema.xml \
+ $(srcdir)/qpid/acl/management-schema.xml \
+ $(srcdir)/qpid/cluster/management-schema.xml
+
+$(srcdir)/managementgen.mk $(mgen_broker_cpp) $(dist_qpid_management_HEADERS): mgen.timestamp
+mgen.timestamp: $(mgen_generator)
+ $(mgen_cmd); touch $@
+$(mgen_generator):
+
+endif # GENERATE
+
+include $(srcdir)/rubygen.mk
+include $(srcdir)/managementgen.mk
+
+# Code generated by C++
+noinst_PROGRAMS=generate_MaxMethodBodySize_h
+generate_MaxMethodBodySize_h_SOURCES=gen/generate_MaxMethodBodySize_h.cpp
+qpid/framing/MaxMethodBodySize.h: generate_MaxMethodBodySize_h
+ ./generate_MaxMethodBodySize_h
+BUILT_SOURCES=qpid/framing/MaxMethodBodySize.h
+DISTCLEANFILES=qpid/framing/MaxMethodBodySize.h
+
+## Compiler flags
+AM_CXXFLAGS = $(WARNING_CFLAGS)
+AM_LDFLAGS = -version-info $(LIBTOOL_VERSION_INFO_ARG)
+INCLUDES = -Igen -I$(srcdir)/gen
+
+## Automake macros to build libraries and executables.
+qpidd_CXXFLAGS = $(AM_CXXFLAGS) -DMODULE_DIR=\"$(dmoduledir)\" -DCONF_FILE=\"$(sysconfdir)/qpidd.conf\"
+libqpidclient_la_CXXFLAGS = $(AM_CXXFLAGS) -DMODULE_DIR=\"$(cmoduledir)\" -DCONF_FILE=\"$(confdir)/qpidc.conf\"
+
+qpidd_LDADD = \
+ libqpidbroker.la \
+ libqpidcommon.la
+
+posix_qpidd_src = posix/QpiddBroker.cpp
+
+sbin_PROGRAMS = qpidd
+qpidd_SOURCES = qpidd.cpp qpidd.h $(posix_qpidd_src)
+
+posix_plat_src = \
+ qpid/log/posix/SinkOptions.cpp \
+ qpid/sys/posix/IOHandle.cpp \
+ qpid/sys/posix/Socket.cpp \
+ qpid/sys/posix/AsynchIO.cpp \
+ qpid/sys/posix/FileSysDir.cpp \
+ qpid/sys/posix/LockFile.cpp \
+ qpid/sys/posix/Time.cpp \
+ qpid/sys/posix/Thread.cpp \
+ qpid/sys/posix/Shlib.cpp \
+ qpid/sys/posix/SystemInfo.cpp \
+ qpid/sys/posix/Mutex.cpp \
+ qpid/sys/posix/Fork.cpp \
+ qpid/sys/posix/StrError.cpp \
+ qpid/sys/posix/PollableCondition.cpp
+
+posix_plat_hdr = \
+ qpid/log/posix/SinkOptions.h \
+ qpid/sys/posix/check.h \
+ qpid/sys/posix/Condition.h \
+ qpid/sys/posix/PrivatePosix.h \
+ qpid/sys/posix/Mutex.h \
+ qpid/sys/posix/Fork.h \
+ qpid/sys/posix/PollableCondition.h \
+ qpid/sys/posix/IntegerTypes.h \
+ qpid/sys/posix/Time.h
+
+if HAVE_EPOLL
+ poller = qpid/sys/epoll/EpollPoller.cpp
+endif
+
+if HAVE_ECF
+ poller = qpid/sys/solaris/ECFPoller.cpp
+endif
+
+platform_src = $(posix_plat_src) $(poller)
+platform_hdr = $(posix_plat_hdr)
+
+posix_broker_src = \
+ qpid/broker/posix/BrokerDefaults.cpp
+
+lib_LTLIBRARIES = libqpidcommon.la libqpidbroker.la libqpidclient.la
+
+# Definitions for client and daemon plugins
+PLUGINLDFLAGS=-no-undefined -module -avoid-version
+confdir=$(sysconfdir)/qpid
+dmoduledir=$(libdir)/qpid/daemon
+cmoduledir=$(libdir)/qpid/client
+dmodule_LTLIBRARIES =
+cmodule_LTLIBRARIES =
+module_hdr =
+
+include cluster.mk
+include acl.mk
+include qmf.mk
+include qmfc.mk
+if HAVE_XML
+include xml.mk
+endif
+
+if RDMA
+
+# RDMA (Infiniband) protocol code
+librdmawrap_la_SOURCES = \
+ qpid/sys/rdma/rdma_exception.h \
+ qpid/sys/rdma/rdma_factories.cpp \
+ qpid/sys/rdma/rdma_factories.h \
+ qpid/sys/rdma/RdmaIO.cpp \
+ qpid/sys/rdma/RdmaIO.h \
+ qpid/sys/rdma/rdma_wrap.cpp \
+ qpid/sys/rdma/rdma_wrap.h
+librdmawrap_la_LIBADD = \
+ libqpidcommon.la \
+ -lrdmacm \
+ -libverbs
+librdmawrap_la_CXXFLAGS = \
+ $(AM_CXXFLAGS) -Wno-missing-field-initializers
+lib_LTLIBRARIES += \
+ librdmawrap.la
+librdmawrap_la_LDFLAGS = \
+ -no-undefined
+
+rdma_la_SOURCES = \
+ qpid/sys/RdmaIOPlugin.cpp
+rdma_la_LIBADD = \
+ libqpidbroker.la \
+ librdmawrap.la
+rdma_la_LDFLAGS = $(PLUGINLDFLAGS)
+rdma_la_CXXFLAGS = \
+ $(AM_CXXFLAGS) -Wno-missing-field-initializers
+dmodule_LTLIBRARIES += \
+ rdma.la
+
+rdmaconnector_la_SOURCES = \
+ qpid/client/RdmaConnector.cpp
+rdmaconnector_la_LIBADD = \
+ libqpidclient.la \
+ librdmawrap.la
+rdmaconnector_la_LDFLAGS = $(PLUGINLDFLAGS)
+rdmaconnector_la_CXXFLAGS = \
+ $(AM_CXXFLAGS) -Wno-missing-field-initializers
+cmodule_LTLIBRARIES += \
+ rdmaconnector.la
+
+# RDMA test/sample programs
+noinst_PROGRAMS += RdmaServer RdmaClient
+RdmaServer_SOURCES = qpid/sys/rdma/RdmaServer.cpp
+RdmaServer_LDADD = \
+ librdmawrap.la libqpidcommon.la
+RdmaClient_SOURCES = qpid/sys/rdma/RdmaClient.cpp
+RdmaClient_CXXFLAGS = \
+ $(AM_CXXFLAGS) -Wno-missing-field-initializers
+RdmaClient_LDADD = \
+ librdmawrap.la libqpidcommon.la
+
+endif
+
+if SSL
+include ssl.mk
+endif
+
+# New 0-10 codec, to be integrated in future.
+# libqpidamqp_0_10_la_SOURCES=
+EXTRA_DIST +=\
+ $(rgen_amqp_0_10_srcs) \
+ qpid/amqp_0_10/apply.h \
+ qpid/amqp_0_10/built_in_types.h \
+ qpid/amqp_0_10/complex_types.cpp \
+ qpid/amqp_0_10/Array.h \
+ qpid/amqp_0_10/Array.cpp \
+ qpid/amqp_0_10/Body.h \
+ qpid/amqp_0_10/Command.h \
+ qpid/amqp_0_10/CommmandPacker.h \
+ qpid/amqp_0_10/Control.h \
+ qpid/amqp_0_10/Header.h \
+ qpid/amqp_0_10/Header.cpp \
+ qpid/amqp_0_10/FrameHeader.h \
+ qpid/amqp_0_10/FrameHeader.cpp \
+ qpid/amqp_0_10/Holder.h \
+ qpid/amqp_0_10/Codec.h \
+ qpid/amqp_0_10/Packer.h \
+ qpid/amqp_0_10/Decimal.h \
+ qpid/amqp_0_10/SerializableString.h \
+ qpid/amqp_0_10/Map.h \
+ qpid/amqp_0_10/Map.cpp \
+ qpid/amqp_0_10/Struct.h \
+ qpid/amqp_0_10/Struct32.h \
+ qpid/amqp_0_10/Struct32.cpp \
+ qpid/amqp_0_10/Unit.h \
+ qpid/amqp_0_10/Unit.cpp \
+ qpid/amqp_0_10/UnitHandler.h \
+ qpid/amqp_0_10/UnknownType.h \
+ qpid/amqp_0_10/UnknownType.cpp \
+ qpid/amqp_0_10/UnknownStruct.h \
+ qpid/amqp_0_10/UnknownStruct.cpp
+
+libqpidcommon_la_LIBADD = \
+ -lboost_program_options \
+ -lboost_filesystem \
+ -luuid \
+ $(LIB_DLOPEN) \
+ $(LIB_CLOCK_GETTIME)
+
+libqpidcommon_la_SOURCES = \
+ $(rgen_framing_srcs) \
+ $(platform_src) \
+ qpid/assert.cpp qpid/assert.h \
+ qpid/pointer_to_other.h \
+ qpid/Address.cpp \
+ qpid/DataDir.cpp \
+ qpid/Exception.cpp \
+ qpid/Modules.cpp \
+ qpid/Options.cpp \
+ qpid/Plugin.cpp \
+ qpid/RefCountedBuffer.h \
+ qpid/RefCountedBuffer.cpp \
+ qpid/Serializer.h \
+ qpid/SessionState.h \
+ qpid/SessionState.cpp \
+ qpid/SessionId.cpp \
+ qpid/StringUtils.cpp \
+ qpid/Url.cpp \
+ qpid/amqp_0_10/SessionHandler.h \
+ qpid/amqp_0_10/SessionHandler.cpp \
+ qpid/framing/AccumulatedAck.cpp \
+ qpid/framing/AMQBody.cpp \
+ qpid/framing/AMQMethodBody.cpp \
+ qpid/framing/AMQContentBody.cpp \
+ qpid/framing/AMQFrame.cpp \
+ qpid/framing/AMQHeaderBody.cpp \
+ qpid/framing/AMQHeartbeatBody.cpp \
+ qpid/framing/Array.cpp \
+ qpid/framing/BodyHolder.cpp \
+ qpid/framing/BodyHandler.cpp \
+ qpid/framing/Buffer.cpp \
+ qpid/framing/Endian.cpp \
+ qpid/framing/FieldTable.cpp \
+ qpid/framing/FieldValue.cpp \
+ qpid/framing/FrameSet.cpp \
+ qpid/framing/FrameDecoder.cpp \
+ qpid/framing/ProtocolInitiation.cpp \
+ qpid/framing/ProtocolVersion.cpp \
+ qpid/framing/SendContent.cpp \
+ qpid/framing/SequenceNumber.cpp \
+ qpid/framing/SequenceNumberSet.cpp \
+ qpid/framing/SequenceSet.cpp \
+ qpid/framing/Proxy.cpp \
+ qpid/framing/Uuid.cpp \
+ qpid/framing/AMQP_HighestVersion.h \
+ qpid/framing/Blob.cpp \
+ qpid/framing/MaxMethodBodySize.h \
+ qpid/framing/TransferContent.cpp \
+ qpid/log/Logger.cpp \
+ qpid/log/Options.cpp \
+ qpid/log/OstreamOutput.cpp \
+ qpid/log/Selector.cpp \
+ qpid/log/Statement.cpp \
+ qpid/management/Manageable.cpp \
+ qpid/management/ManagementObject.cpp \
+ qpid/sys/AggregateOutput.cpp \
+ qpid/sys/AsynchIOHandler.cpp \
+ qpid/sys/Dispatcher.cpp \
+ qpid/sys/DispatchHandle.cpp \
+ qpid/sys/PollableCondition.h \
+ qpid/sys/PollableQueue.h \
+ qpid/sys/Runnable.cpp \
+ qpid/sys/Shlib.cpp
+
+libqpidbroker_la_LIBADD = libqpidcommon.la -luuid
+if HAVE_SASL
+libqpidbroker_la_LIBADD += -lsasl2
+endif
+
+libqpidbroker_la_SOURCES = \
+ $(mgen_broker_cpp) \
+ $(posix_broker_src) \
+ qpid/amqp_0_10/Connection.h \
+ qpid/amqp_0_10/Connection.cpp \
+ qpid/broker/Broker.cpp \
+ qpid/broker/BrokerSingleton.cpp \
+ qpid/broker/Exchange.cpp \
+ qpid/broker/Queue.cpp \
+ qpid/broker/QueueCleaner.cpp \
+ qpid/broker/QueueListeners.cpp \
+ qpid/broker/PersistableMessage.cpp \
+ qpid/broker/Bridge.cpp \
+ qpid/broker/Connection.cpp \
+ qpid/broker/ConnectionHandler.cpp \
+ qpid/broker/ConnectionFactory.cpp \
+ qpid/broker/Daemon.cpp \
+ qpid/broker/DeliverableMessage.cpp \
+ qpid/broker/DeliveryRecord.cpp \
+ qpid/broker/DirectExchange.cpp \
+ qpid/broker/DtxAck.cpp \
+ qpid/broker/DtxBuffer.cpp \
+ qpid/broker/DtxManager.cpp \
+ qpid/broker/DtxTimeout.cpp \
+ qpid/broker/DtxWorkRecord.cpp \
+ qpid/broker/ExchangeRegistry.cpp \
+ qpid/broker/FanOutExchange.cpp \
+ qpid/broker/HeadersExchange.cpp \
+ qpid/broker/IncompleteMessageList.cpp \
+ qpid/broker/Link.cpp \
+ qpid/broker/LinkRegistry.cpp \
+ qpid/broker/Message.cpp \
+ qpid/broker/MessageAdapter.cpp \
+ qpid/broker/MessageBuilder.cpp \
+ qpid/broker/MessageStoreModule.cpp \
+ qpid/broker/NameGenerator.cpp \
+ qpid/broker/NullMessageStore.cpp \
+ qpid/broker/QueueBindings.cpp \
+ qpid/broker/QueuePolicy.cpp \
+ qpid/broker/QueueRegistry.cpp \
+ qpid/broker/RateTracker.cpp \
+ qpid/broker/RecoveryManagerImpl.cpp \
+ qpid/broker/RecoveredEnqueue.cpp \
+ qpid/broker/RecoveredDequeue.cpp \
+ qpid/broker/SaslAuthenticator.cpp \
+ qpid/broker/SemanticState.h \
+ qpid/broker/SemanticState.cpp \
+ qpid/broker/SessionAdapter.cpp \
+ qpid/broker/SessionState.h \
+ qpid/broker/SessionState.cpp \
+ qpid/broker/SessionManager.h \
+ qpid/broker/SessionManager.cpp \
+ qpid/broker/SessionContext.h \
+ qpid/broker/SessionHandler.h \
+ qpid/broker/SessionHandler.cpp \
+ qpid/broker/SignalHandler.h \
+ qpid/broker/SignalHandler.cpp \
+ qpid/broker/System.cpp \
+ qpid/broker/Timer.cpp \
+ qpid/broker/TopicExchange.cpp \
+ qpid/broker/TxAccept.cpp \
+ qpid/broker/TxBuffer.cpp \
+ qpid/broker/TxPublish.cpp \
+ qpid/broker/Vhost.cpp \
+ qpid/management/ManagementBroker.cpp \
+ qpid/management/ManagementExchange.cpp \
+ qpid/sys/TCPIOPlugin.cpp
+
+libqpidclient_la_LIBADD = libqpidcommon.la -luuid
+
+libqpidclient_la_SOURCES = \
+ $(rgen_client_srcs) \
+ qpid/client/Bounds.cpp \
+ qpid/client/Connection.cpp \
+ qpid/client/ConnectionHandler.cpp \
+ qpid/client/ConnectionImpl.cpp \
+ qpid/client/ConnectionSettings.cpp \
+ qpid/client/Connector.cpp \
+ qpid/client/Demux.cpp \
+ qpid/client/Dispatcher.cpp \
+ qpid/client/FailoverManager.cpp \
+ qpid/client/FailoverListener.h \
+ qpid/client/FailoverListener.cpp \
+ qpid/client/Future.cpp \
+ qpid/client/FutureCompletion.cpp \
+ qpid/client/FutureResult.cpp \
+ qpid/client/HandlePrivate.h \
+ qpid/client/LoadPlugins.cpp \
+ qpid/client/LocalQueue.cpp \
+ qpid/client/Message.cpp \
+ qpid/client/MessageListener.cpp \
+ qpid/client/MessageReplayTracker.cpp \
+ qpid/client/QueueOptions.cpp \
+ qpid/client/Results.cpp \
+ qpid/client/SessionBase_0_10.cpp \
+ qpid/client/SessionBase_0_10.h \
+ qpid/client/SessionBase_0_10Access.h \
+ qpid/client/ConnectionAccess.h \
+ qpid/client/SessionImpl.cpp \
+ qpid/client/StateManager.cpp \
+ qpid/client/Subscription.cpp \
+ qpid/client/SubscriptionImpl.cpp \
+ qpid/client/SubscriptionManager.cpp
+
+nobase_include_HEADERS = \
+ $(platform_hdr) \
+ $(module_hdr) \
+ qpid/amqp_0_10/apply.h \
+ qpid/assert.h \
+ qpid/Address.h \
+ qpid/DataDir.h \
+ qpid/Exception.h \
+ qpid/sys/ExceptionHolder.h \
+ qpid/amqp_0_10/Exception.h \
+ qpid/Modules.h \
+ qpid/Msg.h \
+ qpid/Options.h \
+ qpid/Plugin.h \
+ qpid/ptr_map.h \
+ qpid/RangeSet.h \
+ qpid/RefCounted.h \
+ qpid/SessionId.h \
+ qpid/SessionState.h \
+ qpid/SharedObject.h \
+ qpid/StringUtils.h \
+ qpid/Url.h \
+ qpid/InlineVector.h \
+ qpid/InlineAllocator.h \
+ qpid/memory.h \
+ qpid/shared_ptr.h \
+ qpid/Version.h \
+ qpid/broker/Broker.h \
+ qpid/broker/AclModule.h \
+ qpid/broker/SessionAdapter.h \
+ qpid/broker/Exchange.h \
+ qpid/broker/Queue.h \
+ qpid/broker/QueueListeners.h \
+ qpid/broker/QueueCleaner.h \
+ qpid/broker/BrokerSingleton.h \
+ qpid/broker/Bridge.h \
+ qpid/broker/Connection.h \
+ qpid/broker/ConnectionState.h \
+ qpid/broker/ConnectionFactory.h \
+ qpid/broker/ConnectionHandler.h \
+ qpid/broker/ConnectionToken.h \
+ qpid/broker/OwnershipToken.h \
+ qpid/broker/Consumer.h \
+ qpid/broker/Daemon.h \
+ qpid/broker/Deliverable.h \
+ qpid/broker/DeliverableMessage.h \
+ qpid/broker/DeliveryAdapter.h \
+ qpid/broker/DeliveryId.h \
+ qpid/broker/DeliveryRecord.h \
+ qpid/broker/DirectExchange.h \
+ qpid/broker/DtxAck.h \
+ qpid/broker/DtxBuffer.h \
+ qpid/broker/DtxManager.h \
+ qpid/broker/DtxTimeout.h \
+ qpid/broker/DtxWorkRecord.h \
+ qpid/broker/ExchangeRegistry.h \
+ qpid/broker/FanOutExchange.h \
+ qpid/broker/HandlerImpl.h \
+ qpid/broker/HeadersExchange.h \
+ qpid/broker/IncompleteMessageList.h \
+ qpid/broker/Link.h \
+ qpid/broker/LinkRegistry.h \
+ qpid/broker/Message.h \
+ qpid/broker/MessageAdapter.h \
+ qpid/broker/MessageBuilder.h \
+ qpid/broker/MessageStore.h \
+ qpid/broker/MessageStoreModule.h \
+ qpid/broker/NameGenerator.h \
+ qpid/broker/NullMessageStore.h \
+ qpid/broker/Persistable.h \
+ qpid/broker/PersistableConfig.h \
+ qpid/broker/PersistableExchange.h \
+ qpid/broker/PersistableMessage.h \
+ qpid/broker/PersistableQueue.h \
+ qpid/broker/QueueBindings.h \
+ qpid/broker/QueuedMessage.h \
+ qpid/broker/QueuePolicy.h \
+ qpid/broker/QueueRegistry.h \
+ qpid/broker/RateTracker.h \
+ qpid/broker/RecoverableConfig.h \
+ qpid/broker/RecoverableExchange.h \
+ qpid/broker/RecoverableMessage.h \
+ qpid/broker/RecoverableQueue.h \
+ qpid/broker/RecoverableTransaction.h \
+ qpid/broker/RecoveredDequeue.h \
+ qpid/broker/RecoveredEnqueue.h \
+ qpid/broker/RecoveryManager.h \
+ qpid/broker/RecoveryManagerImpl.h \
+ qpid/broker/SaslAuthenticator.h \
+ qpid/broker/SessionAdapter.h \
+ qpid/broker/SessionManager.h \
+ qpid/broker/System.h \
+ qpid/broker/Timer.h \
+ qpid/broker/TopicExchange.h \
+ qpid/broker/TransactionalStore.h \
+ qpid/broker/TxAccept.h \
+ qpid/broker/TxBuffer.h \
+ qpid/broker/TxOp.h \
+ qpid/broker/TxOpVisitor.h \
+ qpid/broker/TxPublish.h \
+ qpid/broker/Vhost.h \
+ qpid/client/AckMode.h \
+ qpid/client/Bounds.h \
+ qpid/client/ChainableFrameHandler.h \
+ qpid/client/Completion.h \
+ qpid/client/Connection.h \
+ qpid/client/ConnectionHandler.h \
+ qpid/client/ConnectionImpl.h \
+ qpid/client/ConnectionSettings.h \
+ qpid/client/Connector.h \
+ qpid/client/Demux.h \
+ qpid/client/Dispatcher.h \
+ qpid/client/Execution.h \
+ qpid/client/FailoverManager.h \
+ qpid/client/Subscription.h \
+ qpid/client/SubscriptionImpl.h \
+ qpid/client/SubscriptionSettings.h \
+ qpid/client/FlowControl.h \
+ qpid/client/Future.h \
+ qpid/client/FutureCompletion.h \
+ qpid/client/FutureResult.h \
+ qpid/client/Handle.h \
+ qpid/client/LocalQueue.h \
+ qpid/client/QueueOptions.h \
+ qpid/client/Message.h \
+ qpid/client/MessageListener.h \
+ qpid/client/MessageReplayTracker.h \
+ qpid/client/Results.h \
+ qpid/client/SessionBase_0_10.h \
+ qpid/client/Session.h \
+ qpid/client/SessionImpl.h \
+ qpid/client/AsyncSession.h \
+ qpid/client/StateManager.h \
+ qpid/client/SubscriptionManager.h \
+ qpid/client/TypedResult.h \
+ qpid/framing/AMQBody.h \
+ qpid/framing/AMQCommandControlBody.h \
+ qpid/framing/AMQContentBody.h \
+ qpid/framing/AMQDataBlock.h \
+ qpid/framing/AMQFrame.h \
+ qpid/framing/AMQHeaderBody.h \
+ qpid/framing/AMQHeartbeatBody.h \
+ qpid/framing/AMQMethodBody.h \
+ qpid/framing/AMQP_HighestVersion.h \
+ qpid/framing/AccumulatedAck.h \
+ qpid/framing/Array.h \
+ qpid/framing/Blob.h \
+ qpid/framing/BodyHandler.h \
+ qpid/framing/BodyHolder.h \
+ qpid/framing/Buffer.h \
+ qpid/framing/ChannelHandler.h \
+ qpid/framing/Endian.h \
+ qpid/framing/FieldTable.h \
+ qpid/framing/FieldValue.h \
+ qpid/framing/FrameDefaultVisitor.h \
+ qpid/framing/FrameDecoder.h \
+ qpid/framing/FrameHandler.h \
+ qpid/framing/FrameSet.h \
+ qpid/framing/Handler.h \
+ qpid/framing/HeaderProperties.h \
+ qpid/framing/Invoker.h \
+ qpid/framing/InputHandler.h \
+ qpid/framing/InitiationHandler.h \
+ qpid/framing/MethodContent.h \
+ qpid/framing/MaxMethodBodySize.h \
+ qpid/framing/ModelMethod.h \
+ qpid/framing/OutputHandler.h \
+ qpid/framing/ProtocolInitiation.h \
+ qpid/framing/ProtocolVersion.h \
+ qpid/framing/Proxy.h \
+ qpid/framing/SendContent.h \
+ qpid/framing/SequenceNumber.h \
+ qpid/framing/SequenceSet.h \
+ qpid/framing/SequenceNumberSet.h \
+ qpid/framing/StructHelper.h \
+ qpid/framing/TransferContent.h \
+ qpid/framing/TypeFilter.h \
+ qpid/framing/Uuid.h \
+ qpid/framing/Visitor.h \
+ qpid/framing/amqp_framing.h \
+ qpid/framing/amqp_types.h \
+ qpid/framing/amqp_types_full.h \
+ qpid/framing/frame_functors.h \
+ qpid/framing/variant.h \
+ qpid/log/Helpers.h \
+ qpid/log/Options.h \
+ qpid/log/Logger.h \
+ qpid/log/OstreamOutput.h \
+ qpid/log/Selector.h \
+ qpid/log/SinkOptions.h \
+ qpid/log/Statement.h \
+ qpid/management/Args.h \
+ qpid/management/Manageable.h \
+ qpid/management/ManagementBroker.h \
+ qpid/management/ManagementEvent.h \
+ qpid/management/ManagementExchange.h \
+ qpid/management/ManagementObject.h \
+ qpid/sys/AggregateOutput.h \
+ qpid/sys/AsynchIO.h \
+ qpid/sys/AsynchIOHandler.h \
+ qpid/sys/AtomicCount.h \
+ qpid/sys/AtomicValue.h \
+ qpid/sys/AtomicValue_gcc.h \
+ qpid/sys/AtomicValue_mutex.h \
+ qpid/sys/BlockingQueue.h \
+ qpid/sys/CopyOnWriteArray.h \
+ qpid/sys/Condition.h \
+ qpid/sys/ConnectionCodec.h \
+ qpid/sys/ConnectionInputHandler.h \
+ qpid/sys/ConnectionInputHandlerFactory.h \
+ qpid/sys/ConnectionOutputHandler.h \
+ qpid/sys/ConnectionOutputHandlerPtr.h \
+ qpid/sys/DeletionManager.h \
+ qpid/sys/Dispatcher.h \
+ qpid/sys/DispatchHandle.h \
+ qpid/sys/FileSysDir.h \
+ qpid/sys/IntegerTypes.h \
+ qpid/sys/IOHandle.h \
+ qpid/sys/LockFile.h \
+ qpid/sys/LockPtr.h \
+ qpid/sys/Monitor.h \
+ qpid/sys/Mutex.h \
+ qpid/sys/OutputControl.h \
+ qpid/sys/OutputTask.h \
+ qpid/sys/Poller.h \
+ qpid/sys/ProtocolFactory.h \
+ qpid/sys/Runnable.h \
+ qpid/sys/Fork.h \
+ qpid/sys/ScopedIncrement.h \
+ qpid/sys/Semaphore.h \
+ qpid/sys/SystemInfo.h \
+ qpid/sys/Shlib.h \
+ qpid/sys/ShutdownHandler.h \
+ qpid/sys/Socket.h \
+ qpid/sys/StateMonitor.h \
+ qpid/sys/StrError.h \
+ qpid/sys/Waitable.h \
+ qpid/sys/Thread.h \
+ qpid/sys/Time.h \
+ qpid/sys/TimeoutHandler.h \
+ qpid/sys/uuid.h
+
+# Force build of qpidd during dist phase so help2man will work.
+dist-hook: $(BUILT_SOURCES)
+ $(MAKE) qpidd
+
+# Create the default data directory
+install-data-local:
+ $(mkinstalldirs) $(DESTDIR)/$(localstatedir)/lib/qpidd
+
diff --git a/RC9/qpid/cpp/src/MaxMethodBodySize.vcproj b/RC9/qpid/cpp/src/MaxMethodBodySize.vcproj
new file mode 100644
index 0000000000..1b1cf67433
--- /dev/null
+++ b/RC9/qpid/cpp/src/MaxMethodBodySize.vcproj
@@ -0,0 +1,396 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="MaxMethodBodySize"
+ ProjectGUID="{CB5C939B-FECA-1BAD-BB9C-8C3A688E2823}"
+ RootNamespace="MaxMethodBodySize"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Static_Debug"
+ IntermediateDirectory="Static_Debug\MaxMethodBodySize\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800;4355"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies=""
+ OutputFile="$(OutDir)\generate_MaxMethodBodySize_h.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="$(OutDir)\generate_MaxMethodBodySize_h"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Static_Release"
+ IntermediateDirectory="Static_Release\MaxMethodBodySize\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX"
+ RuntimeLibrary="0"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800;4355"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies=""
+ OutputFile="$(OutDir)\generate_MaxMethodBodySize_h.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="$(OutDir)\generate_MaxMethodBodySize_h"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="Static_Debug"
+ IntermediateDirectory="Static_Debug\MaxMethodBodySize\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800;4355"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies=""
+ OutputFile="$(OutDir)\generate_MaxMethodBodySize_h.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="$(OutDir)\generate_MaxMethodBodySize_h"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Static_Release"
+ IntermediateDirectory="Static_Release\MaxMethodBodySize\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX"
+ RuntimeLibrary="0"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800;4355"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies=""
+ OutputFile="$(OutDir)\generate_MaxMethodBodySize_h.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="$(OutDir)\generate_MaxMethodBodySize_h"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;C;c">
+ <File
+ RelativePath="gen\generate_MaxMethodBodySize_h.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hh">
+ <File
+ RelativePath="qpidd.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/RC9/qpid/cpp/src/acl.mk b/RC9/qpid/cpp/src/acl.mk
new file mode 100644
index 0000000000..2b3ab4dfd9
--- /dev/null
+++ b/RC9/qpid/cpp/src/acl.mk
@@ -0,0 +1,34 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+# acl library makefile fragment, to be included in Makefile.am
+#
+dmodule_LTLIBRARIES += acl.la
+
+acl_la_SOURCES = \
+ qpid/acl/Acl.cpp \
+ qpid/acl/Acl.h \
+ qpid/acl/AclData.cpp \
+ qpid/acl/AclData.h \
+ qpid/acl/AclPlugin.cpp \
+ qpid/acl/AclReader.cpp \
+ qpid/acl/AclReader.h
+
+acl_la_LIBADD = libqpidbroker.la
+acl_la_LDFLAGS = $(PLUGINLDFLAGS)
diff --git a/RC9/qpid/cpp/src/broker.vcproj b/RC9/qpid/cpp/src/broker.vcproj
new file mode 100644
index 0000000000..aaa7c0ce54
--- /dev/null
+++ b/RC9/qpid/cpp/src/broker.vcproj
@@ -0,0 +1,1280 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="broker"
+ ProjectGUID="{09613D48-FECA-1BAD-9D20-8C37688E2823}"
+ RootNamespace="broker"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Static_Debug"
+ IntermediateDirectory="Static_Debug\broker\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800;4290;4355"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommonsd.lib ws2_32.lib secur32.lib rpcrt4.lib"
+ OutputFile="$(OutDir)\qpidbroker.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Static_Release"
+ IntermediateDirectory="Static_Release\broker\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="0"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800;4290;4355"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommons.lib ws2_32.lib secur32.lib rpcrt4.lib"
+ OutputFile="$(OutDir)\qpidbroker.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="Static_Debug"
+ IntermediateDirectory="Static_Debug\broker\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800;4290;4355"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommonsd.lib ws2_32.lib secur32.lib rpcrt4.lib"
+ OutputFile="$(OutDir)\qpidbroker.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Static_Release"
+ IntermediateDirectory="Static_Release\broker\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="0"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800;4290;4355"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommons.lib ws2_32.lib secur32.lib rpcrt4.lib"
+ OutputFile="$(OutDir)\qpidbroker.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;C;c">
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\acl\Acl.cpp">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\acl\EventAllow.cpp">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\acl\EventDeny.cpp">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\acl\EventFileLoaded.cpp">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\acl\EventFileLoadFailed.cpp">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\acl\Package.cpp">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\Agent.cpp">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\Binding.cpp">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\Bridge.cpp">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\Broker.cpp">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\Connection.cpp">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\EventBind.cpp">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\EventBrokerLinkDown.cpp">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\EventBrokerLinkUp.cpp">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\EventClientConnect.cpp">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\EventClientConnectFail.cpp">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\EventClientDisconnect.cpp">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\EventExchangeDeclare.cpp">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\EventExchangeDelete.cpp">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\EventQueueDeclare.cpp">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\EventQueueDelete.cpp">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\EventSubscribe.cpp">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\EventUnbind.cpp">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\EventUnsubscribe.cpp">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\Exchange.cpp">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\Link.cpp">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\Package.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\Queue.cpp">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\Session.cpp">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\System.cpp">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\Vhost.cpp">
+ </File>
+ <File
+ RelativePath="qpid\amqp_0_10\Connection.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="qpid\amqp_0_10\Connection.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\Bridge.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="qpid\broker\Broker.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="qpid\broker\BrokerSingleton.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\Connection.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)3.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)3.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)3.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)3.obj"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="qpid\broker\ConnectionFactory.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\ConnectionHandler.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\DeliverableMessage.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\DeliveryRecord.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\DirectExchange.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\DtxAck.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\DtxBuffer.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\DtxManager.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\DtxTimeout.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\DtxWorkRecord.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\Exchange.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="qpid\broker\ExchangeRegistry.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\FanOutExchange.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\HeadersExchange.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\IncompleteMessageList.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\Link.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="qpid\broker\LinkRegistry.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\Message.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\MessageAdapter.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\MessageBuilder.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\MessageStoreModule.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\NameGenerator.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\NullMessageStore.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\PersistableMessage.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\Queue.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="qpid\broker\QueueBindings.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\QueueCleaner.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\QueueListeners.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\QueuePolicy.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\QueueRegistry.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\RateTracker.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\RecoveredDequeue.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\RecoveredEnqueue.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\RecoveryManagerImpl.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\SemanticState.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\SemanticState.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\SessionAdapter.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\SessionContext.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\SessionHandler.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\SessionHandler.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\SessionManager.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\SessionManager.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\SessionState.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\SessionState.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\System.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="qpid\broker\Timer.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\TopicExchange.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\TxAccept.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\TxBuffer.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\TxPublish.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\Vhost.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="qpid\broker\windows\BrokerDefaults.cpp">
+ </File>
+ <File
+ RelativePath="qpid\broker\windows\SaslAuthenticator.cpp">
+ </File>
+ <File
+ RelativePath="qpid\management\ManagementBroker.cpp">
+ </File>
+ <File
+ RelativePath="qpid\management\ManagementExchange.cpp">
+ </File>
+ <File
+ RelativePath="qpid\sys\TCPIOPlugin.cpp">
+ </File>
+ <File
+ RelativePath="qpidd.cpp">
+ </File>
+ <File
+ RelativePath="windows\QpiddBroker.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hh">
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\acl\Acl.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\acl\EventAllow.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\acl\EventDeny.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\acl\EventFileLoaded.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\acl\EventFileLoadFailed.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\acl\Package.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\Agent.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\ArgsBrokerConnect.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\ArgsBrokerEcho.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\ArgsBrokerQueueMoveMessages.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\ArgsLinkBridge.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\ArgsQueuePurge.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\Binding.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\Bridge.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\Broker.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\Connection.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\EventBind.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\EventBrokerLinkDown.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\EventBrokerLinkUp.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\EventClientConnect.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\EventClientConnectFail.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\EventClientDisconnect.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\EventExchangeDeclare.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\EventExchangeDelete.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\EventQueueDeclare.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\EventQueueDelete.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\EventSubscribe.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\EventUnbind.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\EventUnsubscribe.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\Exchange.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\Link.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\Package.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\Queue.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\Session.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\System.h">
+ </File>
+ <File
+ RelativePath="gen\qmf\org\apache\qpid\broker\Vhost.h">
+ </File>
+ <File
+ RelativePath="qpid\amqp_0_10\Connection.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\AclModule.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\Bridge.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\Broker.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\BrokerSingleton.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\Connection.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\ConnectionFactory.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\ConnectionHandler.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\ConnectionState.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\ConnectionToken.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\Consumer.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\Daemon.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\Deliverable.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\DeliverableMessage.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\DeliveryAdapter.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\DeliveryId.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\DeliveryRecord.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\DeliveryToken.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\DirectExchange.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\DtxAck.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\DtxBuffer.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\DtxManager.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\DtxTimeout.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\DtxWorkRecord.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\Exchange.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\ExchangeRegistry.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\FanOutExchange.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\HandlerImpl.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\HeadersExchange.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\IncompleteMessageList.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\Link.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\LinkRegistry.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\Message.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\MessageAdapter.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\MessageBuilder.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\MessageDelivery.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\MessageStore.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\MessageStoreModule.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\NameGenerator.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\NullMessageStore.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\OwnershipToken.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\Persistable.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\PersistableConfig.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\PersistableExchange.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\PersistableMessage.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\PersistableQueue.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\Queue.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\QueueBindings.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\QueueCleaner.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\QueueListeners.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\QueueMessage.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\QueuePolicy.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\QueueRegistry.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\RateTracker.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\RecoverableConfig.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\RecoverableExchange.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\RecoverableMessage.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\RecoverableQueue.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\RecoverableTransaction.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\RecoveredDequeue.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\RecoveredEnqueue.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\RecoveryManager.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\RecoveryManagerImpl.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\SaslAuthenticator.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\SemanticState.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\SessionAdapter.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\SessionContext.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\SessionHandler.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\SessionManager.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\SessionState.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\SignalHandler.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\System.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\Timer.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\TopicExchange.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\TransactionalStore.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\TxAccept.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\TxBuffer.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\TxOp.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\TxOpVisitor.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\TxPublish.h">
+ </File>
+ <File
+ RelativePath="qpid\broker\Vhost.h">
+ </File>
+ <File
+ RelativePath="qpid\management\Args.h">
+ </File>
+ <File
+ RelativePath="qpid\management\Manageable.h">
+ </File>
+ <File
+ RelativePath="qpid\management\ManagementBroker.h">
+ </File>
+ <File
+ RelativePath="qpid\management\ManagementExchange.h">
+ </File>
+ <File
+ RelativePath="qpid\management\ManagementObject.h">
+ </File>
+ <File
+ RelativePath="qpidd.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/RC9/qpid/cpp/src/client.vcproj b/RC9/qpid/cpp/src/client.vcproj
new file mode 100644
index 0000000000..a2d02e9ffc
--- /dev/null
+++ b/RC9/qpid/cpp/src/client.vcproj
@@ -0,0 +1,574 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="client"
+ ProjectGUID="{6961DBA3-FECA-1BAD-F396-8C39688E2823}"
+ RootNamespace="client"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Static_Debug\client\I386"
+ ConfigurationType="4"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ PreprocessorDefinitions="_DEBUG;WIN32;_WINDOWS;_CRT_NONSTDC_NO_WARNINGS;CONF_FILE=\&quot;qpidc.conf\&quot;;MODULE_DIR=\&quot;.\&quot;;NOMINMAX;WIN32_LEAN_AND_MEAN"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800;4355"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;CONF_FILE=\&quot;qpidc.conf\&quot;;MODULE_DIR=\&quot;.\&quot;;NOMINMAX;WIN32_LEAN_AND_MEAN"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile=".\qpidclientsd.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Static_Release\client\I386"
+ ConfigurationType="4"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;_CRT_NONSTDC_NO_WARNINGS;CONF_FILE=\&quot;qpidc.conf\&quot;;MODULE_DIR=\&quot;.\&quot;;NOMINMAX;WIN32_LEAN_AND_MEAN"
+ RuntimeLibrary="0"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800;4355"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;CONF_FILE=\&quot;qpidc.conf\&quot;;MODULE_DIR=\&quot;.\&quot;;NOMINMAX;WIN32_LEAN_AND_MEAN"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile=".\qpidclients.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Static_Debug\client\AMD64"
+ ConfigurationType="4"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ PreprocessorDefinitions="_DEBUG;WIN32;_WINDOWS;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;CONF_FILE=\&quot;qpidc.conf\&quot;;MODULE_DIR=\&quot;.\&quot;;NOMINMAX;WIN32_LEAN_AND_MEAN"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800;4355"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;CONF_FILE=\&quot;qpidc.conf\&quot;;MODULE_DIR=\&quot;.\&quot;;NOMINMAX;WIN32_LEAN_AND_MEAN;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile=".\qpidclientsd.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Static_Release\client\AMD64"
+ ConfigurationType="4"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;CONF_FILE=\&quot;qpidc.conf\&quot;;MODULE_DIR=\&quot;.\&quot;;NOMINMAX;WIN32_LEAN_AND_MEAN"
+ RuntimeLibrary="0"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800;4355"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;CONF_FILE=\&quot;qpidc.conf\&quot;;MODULE_DIR=\&quot;.\&quot;;NOMINMAX;WIN32_LEAN_AND_MEAN;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile=".\qpidclients.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;C;c">
+ <File
+ RelativePath="gen\qpid\client\no_keyword\AsyncSession_0_10.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\client\no_keyword\Session_0_10.cpp">
+ </File>
+ <File
+ RelativePath="qpid\client\Bounds.cpp">
+ </File>
+ <File
+ RelativePath="qpid\client\Connection.cpp">
+ </File>
+ <File
+ RelativePath="qpid\client\ConnectionAccess.h">
+ </File>
+ <File
+ RelativePath="qpid\client\ConnectionHandler.cpp">
+ </File>
+ <File
+ RelativePath="qpid\client\ConnectionImpl.cpp">
+ </File>
+ <File
+ RelativePath="qpid\client\ConnectionSettings.cpp">
+ </File>
+ <File
+ RelativePath="qpid\client\Connector.cpp">
+ </File>
+ <File
+ RelativePath="qpid\client\Demux.cpp">
+ </File>
+ <File
+ RelativePath="qpid\client\Dispatcher.cpp">
+ </File>
+ <File
+ RelativePath="qpid\client\FailoverListener.cpp">
+ </File>
+ <File
+ RelativePath="qpid\client\FailoverListener.h">
+ </File>
+ <File
+ RelativePath="qpid\client\FailoverManager.cpp">
+ </File>
+ <File
+ RelativePath="qpid\client\Future.cpp">
+ </File>
+ <File
+ RelativePath="qpid\client\FutureCompletion.cpp">
+ </File>
+ <File
+ RelativePath="qpid\client\FutureResult.cpp">
+ </File>
+ <File
+ RelativePath="qpid\client\LoadPlugins.cpp">
+ </File>
+ <File
+ RelativePath="qpid\client\LocalQueue.cpp">
+ </File>
+ <File
+ RelativePath="qpid\client\Message.cpp">
+ </File>
+ <File
+ RelativePath="qpid\client\MessageListener.cpp">
+ </File>
+ <File
+ RelativePath="qpid\client\MessageReplayTracker.cpp">
+ </File>
+ <File
+ RelativePath="qpid\client\QueueOptions.cpp">
+ </File>
+ <File
+ RelativePath="qpid\client\Results.cpp">
+ </File>
+ <File
+ RelativePath="qpid\client\SessionBase_0_10.cpp">
+ </File>
+ <File
+ RelativePath="qpid\client\SessionBase_0_10.h">
+ </File>
+ <File
+ RelativePath="qpid\client\SessionBase_0_10Access.h">
+ </File>
+ <File
+ RelativePath="qpid\client\SessionImpl.cpp">
+ </File>
+ <File
+ RelativePath="qpid\client\StateManager.cpp">
+ </File>
+ <File
+ RelativePath="qpid\client\Subscription.cpp">
+ </File>
+ <File
+ RelativePath="qpid\client\SubscriptionImpl.cpp">
+ </File>
+ <File
+ RelativePath="qpid\client\SubscriptionManager.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hh">
+ <File
+ RelativePath="gen\qpid\client\arg.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\client\AsyncSession_0_10.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\client\no_keyword\AsyncSession_0_10.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\client\no_keyword\Session_0_10.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\client\Session_0_10.h">
+ </File>
+ <File
+ RelativePath="qpid\client\AckMode.h">
+ </File>
+ <File
+ RelativePath="qpid\client\AckPolicy.h">
+ </File>
+ <File
+ RelativePath="qpid\client\AsyncSession.h">
+ </File>
+ <File
+ RelativePath="qpid\client\Bounds.h">
+ </File>
+ <File
+ RelativePath="qpid\client\ChainableFrameHandler.h">
+ </File>
+ <File
+ RelativePath="qpid\client\Completion.h">
+ </File>
+ <File
+ RelativePath="qpid\client\Connection.h">
+ </File>
+ <File
+ RelativePath="qpid\client\ConnectionAccess.h">
+ </File>
+ <File
+ RelativePath="qpid\client\ConnectionHandler.h">
+ </File>
+ <File
+ RelativePath="qpid\client\ConnectionImpl.h">
+ </File>
+ <File
+ RelativePath="qpid\client\ConnectionSettings.h">
+ </File>
+ <File
+ RelativePath="qpid\client\Connector.h">
+ </File>
+ <File
+ RelativePath="qpid\client\Demux.h">
+ </File>
+ <File
+ RelativePath="qpid\client\Dispatcher.h">
+ </File>
+ <File
+ RelativePath="qpid\client\Execution.h">
+ </File>
+ <File
+ RelativePath="qpid\client\FailoverListener.h">
+ </File>
+ <File
+ RelativePath="qpid\client\FailoverManager.h">
+ </File>
+ <File
+ RelativePath="qpid\client\FlowControl.h">
+ </File>
+ <File
+ RelativePath="qpid\client\Future.h">
+ </File>
+ <File
+ RelativePath="qpid\client\FutureCompletion.h">
+ </File>
+ <File
+ RelativePath="qpid\client\FutureResult.h">
+ </File>
+ <File
+ RelativePath="qpid\client\LocalQueue.h">
+ </File>
+ <File
+ RelativePath="qpid\client\Message.h">
+ </File>
+ <File
+ RelativePath="qpid\client\MessageListener.h">
+ </File>
+ <File
+ RelativePath="qpid\client\MessageReplayTracker.h">
+ </File>
+ <File
+ RelativePath="qpid\client\QueueOptions.h">
+ </File>
+ <File
+ RelativePath="qpid\client\Results.h">
+ </File>
+ <File
+ RelativePath="qpid\client\Session.h">
+ </File>
+ <File
+ RelativePath="qpid\client\SessionBase_0_10.h">
+ </File>
+ <File
+ RelativePath="qpid\client\SessionBase_0_10Access.h">
+ </File>
+ <File
+ RelativePath="qpid\client\SessionImpl.h">
+ </File>
+ <File
+ RelativePath="qpid\client\StateManager.h">
+ </File>
+ <File
+ RelativePath="qpid\client\Subscription.h">
+ </File>
+ <File
+ RelativePath="qpid\client\SubscriptionImpl.h">
+ </File>
+ <File
+ RelativePath="qpid\client\SubscriptionManager.h">
+ </File>
+ <File
+ RelativePath="qpid\client\SubscriptionSettings.h">
+ </File>
+ <File
+ RelativePath="qpid\client\TypedResult.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/RC9/qpid/cpp/src/cluster.mk b/RC9/qpid/cpp/src/cluster.mk
new file mode 100644
index 0000000000..5005004023
--- /dev/null
+++ b/RC9/qpid/cpp/src/cluster.mk
@@ -0,0 +1,75 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+# Cluster library makefile fragment, to be included in Makefile.am
+#
+
+# Optional CMAN support
+
+# Distribute all sources.
+EXTRA_DIST += qpid/cluster/Quorum_cman.h qpid/cluster/Quorum_cman.cpp qpid/cluster/Quorum_null.h
+
+if HAVE_LIBCMAN
+CMAN_SOURCES = qpid/cluster/Quorum_cman.h qpid/cluster/Quorum_cman.cpp
+libcman = -lcman
+else
+CMAN_SOURCES = qpid/cluster/Quorum_null.h
+endif
+
+if HAVE_LIBCPG
+
+dmodule_LTLIBRARIES += cluster.la
+
+cluster_la_SOURCES = \
+ $(CMAN_SOURCES) \
+ qpid/cluster/types.h \
+ qpid/cluster/Cluster.cpp \
+ qpid/cluster/Cluster.h \
+ qpid/cluster/Cpg.cpp \
+ qpid/cluster/Cpg.h \
+ qpid/cluster/Dispatchable.h \
+ qpid/cluster/ClusterPlugin.cpp \
+ qpid/cluster/ConnectionCodec.h \
+ qpid/cluster/ConnectionCodec.cpp \
+ qpid/cluster/Connection.h \
+ qpid/cluster/Connection.cpp \
+ qpid/cluster/ConnectionMap.h \
+ qpid/cluster/NoOpConnectionOutputHandler.h \
+ qpid/cluster/WriteEstimate.h \
+ qpid/cluster/WriteEstimate.cpp \
+ qpid/cluster/OutputInterceptor.h \
+ qpid/cluster/OutputInterceptor.cpp \
+ qpid/cluster/ProxyInputHandler.h \
+ qpid/cluster/Event.h \
+ qpid/cluster/Event.cpp \
+ qpid/cluster/DumpClient.h \
+ qpid/cluster/DumpClient.cpp \
+ qpid/cluster/ClusterMap.h \
+ qpid/cluster/ClusterMap.cpp \
+ qpid/cluster/FailoverExchange.h \
+ qpid/cluster/FailoverExchange.cpp \
+ qpid/cluster/Multicaster.h \
+ qpid/cluster/Multicaster.cpp \
+ qpid/cluster/ClusterLeaveException.h \
+ qpid/cluster/Quorum.h
+
+cluster_la_LIBADD= -lcpg $(libcman) libqpidbroker.la libqpidclient.la
+cluster_la_LDFLAGS = $(PLUGINLDFLAGS)
+
+endif # HAVE_LIBCPG
diff --git a/RC9/qpid/cpp/src/common.vcproj b/RC9/qpid/cpp/src/common.vcproj
new file mode 100644
index 0000000000..39429078f3
--- /dev/null
+++ b/RC9/qpid/cpp/src/common.vcproj
@@ -0,0 +1,1870 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="common"
+ ProjectGUID="{C961EF23-FECA-1BAD-BB9C-8C3A688E2823}"
+ RootNamespace="common"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Static_Debug\common\I386"
+ ConfigurationType="4"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ PreprocessorDefinitions="_DEBUG;WIN32;_WINDOWS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800;4355"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile=".\qpidcommonsd.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Static_Release\common\I386"
+ ConfigurationType="4"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="0"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800;4355"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile=".\qpidcommons.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Static_Debug\common\AMD64"
+ ConfigurationType="4"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ PreprocessorDefinitions="_DEBUG;WIN32;_WINDOWS;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800;4355"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile=".\qpidcommonsd.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Static_Release\common\AMD64"
+ ConfigurationType="4"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="0"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800;4355"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile=".\qpidcommons.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;C;c">
+ <File
+ RelativePath="gen\qpid\framing\AllInvoker.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\AMQP_AllProxy.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\AMQP_ClientProxy.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\AMQP_ServerProxy.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\BodyHolder_gen.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClientInvoker.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConfigChangeBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionAccumulatedAckBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionConsumerStateBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionDeliverCloseBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionDeliverDoOutputBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionDeliveryRecordBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionExchangeBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionMembershipBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionQueueBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionQueuePositionBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionSessionStateBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionShadowReadyBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionTxAcceptBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionTxDequeueBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionTxEndBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionTxEnqueueBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionTxPublishBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionTxStartBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterDumpOfferBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterDumpRequestBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterReadyBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterShutdownBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ConnectionCloseBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ConnectionCloseOkBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ConnectionHeartbeatBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ConnectionOpenBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ConnectionOpenOkBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ConnectionRedirectBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ConnectionSecureBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ConnectionSecureOkBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ConnectionStartBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ConnectionStartOkBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ConnectionTuneBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ConnectionTuneOkBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\DeliveryProperties.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\DtxCommitBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\DtxEndBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\DtxForgetBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\DtxGetTimeoutBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\DtxGetTimeoutResult.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\DtxPrepareBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\DtxRecoverBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\DtxRecoverResult.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\DtxRollbackBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\DtxSelectBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\DtxSetTimeoutBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\DtxStartBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ExchangeBindBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ExchangeBoundBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ExchangeBoundResult.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ExchangeDeclareBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ExchangeDeleteBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ExchangeQueryBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ExchangeQueryResult.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ExchangeUnbindBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ExecutionExceptionBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ExecutionResultBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ExecutionSyncBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FileAckBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FileCancelBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FileConsumeBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FileConsumeOkBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FileDeliverBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FileOpenBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FileOpenOkBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FileProperties.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FilePublishBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FileQosBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FileQosOkBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FileRejectBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FileReturnBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FileStageBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FragmentProperties.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\Header.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageAcceptBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageAcquireBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageAcquireResult.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageCancelBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageFlowBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageFlushBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageProperties.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageRejectBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageReleaseBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageResumeBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageResumeResult.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageSetFlowModeBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageStopBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageSubscribeBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageTransferBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MethodBodyDefaultVisitor.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\QueueDeclareBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\QueueDeleteBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\QueuePurgeBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\QueueQueryBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\QueueQueryResult.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\reply_exceptions.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ReplyTo.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ServerInvoker.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\SessionAttachBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\SessionAttachedBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\SessionCommandPointBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\SessionCompletedBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\SessionConfirmedBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\SessionDetachBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\SessionDetachedBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\SessionExpectedBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\SessionFlushBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\SessionGapBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\SessionKnownCompletedBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\SessionRequestTimeoutBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\SessionTimeoutBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\StreamCancelBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\StreamConsumeBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\StreamConsumeOkBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\StreamDeliverBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\StreamProperties.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\StreamPublishBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\StreamQosBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\StreamQosOkBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\StreamReturnBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\TxCommitBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\TxRollbackBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\TxSelectBody.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\TypeCode.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\XaResult.cpp">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\Xid.cpp">
+ </File>
+ <File
+ RelativePath="qpid\Address.cpp">
+ </File>
+ <File
+ RelativePath="qpid\amqp_0_10\SessionHandler.cpp">
+ </File>
+ <File
+ RelativePath="qpid\amqp_0_10\SessionHandler.h">
+ </File>
+ <File
+ RelativePath="qpid\assert.cpp">
+ </File>
+ <File
+ RelativePath="qpid\assert.h">
+ </File>
+ <File
+ RelativePath="qpid\DataDir.cpp">
+ </File>
+ <File
+ RelativePath="qpid\Exception.cpp">
+ </File>
+ <File
+ RelativePath="qpid\framing\AccumulatedAck.cpp">
+ </File>
+ <File
+ RelativePath="qpid\framing\AMQBody.cpp">
+ </File>
+ <File
+ RelativePath="qpid\framing\AMQContentBody.cpp">
+ </File>
+ <File
+ RelativePath="qpid\framing\AMQFrame.cpp">
+ </File>
+ <File
+ RelativePath="qpid\framing\AMQHeaderBody.cpp">
+ </File>
+ <File
+ RelativePath="qpid\framing\AMQHeartbeatBody.cpp">
+ </File>
+ <File
+ RelativePath="qpid\framing\AMQMethodBody.cpp">
+ </File>
+ <File
+ RelativePath="qpid\framing\AMQP_HighestVersion.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\Array.cpp">
+ </File>
+ <File
+ RelativePath="qpid\framing\Blob.cpp">
+ </File>
+ <File
+ RelativePath="qpid\framing\BodyHandler.cpp">
+ </File>
+ <File
+ RelativePath="qpid\framing\BodyHolder.cpp">
+ </File>
+ <File
+ RelativePath="qpid\framing\Buffer.cpp">
+ </File>
+ <File
+ RelativePath="qpid\framing\Endian.cpp">
+ </File>
+ <File
+ RelativePath="qpid\framing\FieldTable.cpp">
+ </File>
+ <File
+ RelativePath="qpid\framing\FieldValue.cpp">
+ </File>
+ <File
+ RelativePath="qpid\framing\FrameDecoder.cpp">
+ </File>
+ <File
+ RelativePath="qpid\framing\FrameSet.cpp">
+ </File>
+ <File
+ RelativePath="qpid\framing\MaxMethodBodySize.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\ProtocolInitiation.cpp">
+ </File>
+ <File
+ RelativePath="qpid\framing\ProtocolVersion.cpp">
+ </File>
+ <File
+ RelativePath="qpid\framing\Proxy.cpp">
+ </File>
+ <File
+ RelativePath="qpid\framing\SendContent.cpp">
+ </File>
+ <File
+ RelativePath="qpid\framing\SequenceNumber.cpp">
+ </File>
+ <File
+ RelativePath="qpid\framing\SequenceNumberSet.cpp">
+ </File>
+ <File
+ RelativePath="qpid\framing\SequenceSet.cpp">
+ </File>
+ <File
+ RelativePath="qpid\framing\TransferContent.cpp">
+ </File>
+ <File
+ RelativePath="qpid\framing\Uuid.cpp">
+ </File>
+ <File
+ RelativePath="qpid\log\Logger.cpp">
+ </File>
+ <File
+ RelativePath="qpid\log\Options.cpp">
+ </File>
+ <File
+ RelativePath="qpid\log\OstreamOutput.cpp">
+ </File>
+ <File
+ RelativePath="qpid\log\Selector.cpp">
+ </File>
+ <File
+ RelativePath="qpid\log\Statement.cpp">
+ </File>
+ <File
+ RelativePath="qpid\log\windows\SinkOptions.cpp">
+ </File>
+ <File
+ RelativePath="qpid\management\Manageable.cpp">
+ </File>
+ <File
+ RelativePath="qpid\management\ManagementObject.cpp">
+ </File>
+ <File
+ RelativePath="qpid\Modules.cpp">
+ </File>
+ <File
+ RelativePath="qpid\Options.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="qpid\Plugin.cpp">
+ </File>
+ <File
+ RelativePath="qpid\pointer_to_other.h">
+ </File>
+ <File
+ RelativePath="qpid\RefCountedBuffer.cpp">
+ </File>
+ <File
+ RelativePath="qpid\RefCountedBuffer.h">
+ </File>
+ <File
+ RelativePath="qpid\Serializer.h">
+ </File>
+ <File
+ RelativePath="qpid\SessionId.cpp">
+ </File>
+ <File
+ RelativePath="qpid\SessionState.cpp">
+ </File>
+ <File
+ RelativePath="qpid\SessionState.h">
+ </File>
+ <File
+ RelativePath="qpid\StringUtils.cpp">
+ </File>
+ <File
+ RelativePath="qpid\sys\AggregateOutput.cpp">
+ </File>
+ <File
+ RelativePath="qpid\sys\AsynchIOHandler.cpp">
+ </File>
+ <File
+ RelativePath="qpid\sys\PollableCondition.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\PollableQueue.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\Runnable.cpp">
+ </File>
+ <File
+ RelativePath="qpid\sys\Shlib.cpp">
+ </File>
+ <File
+ RelativePath="qpid\sys\windows\AsynchIO.cpp">
+ </File>
+ <File
+ RelativePath="qpid\sys\windows\FileSysDir.cpp">
+ </File>
+ <File
+ RelativePath="qpid\sys\windows\IocpDispatcher.cpp">
+ </File>
+ <File
+ RelativePath="qpid\sys\windows\IocpPoller.cpp">
+ </File>
+ <File
+ RelativePath="qpid\sys\windows\IOHandle.cpp">
+ </File>
+ <File
+ RelativePath="qpid\sys\windows\LockFile.cpp">
+ </File>
+ <File
+ RelativePath="qpid\sys\windows\Shlib.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="qpid\sys\windows\Socket.cpp">
+ </File>
+ <File
+ RelativePath="qpid\sys\windows\StrError.cpp">
+ </File>
+ <File
+ RelativePath="qpid\sys\windows\SystemInfo.cpp">
+ </File>
+ <File
+ RelativePath="qpid\sys\windows\Thread.cpp">
+ </File>
+ <File
+ RelativePath="qpid\sys\windows\Time.cpp">
+ </File>
+ <File
+ RelativePath="qpid\sys\windows\uuid.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64">
+ <Tool
+ Name="VCCLCompilerTool"
+ ObjectFile="$(IntDir)\$(InputName)2.obj"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="qpid\Url.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hh">
+ <File
+ RelativePath="gen\qpid\framing\all_method_bodies.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\AllInvoker.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\AMQP_AllOperations.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\AMQP_AllProxy.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\AMQP_ClientOperations.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\AMQP_ClientProxy.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\AMQP_ServerOperations.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\AMQP_ServerProxy.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\amqp_structs.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClientInvoker.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConfigChangeBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionAccumulatedAckBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionConsumerStateBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionDeliverCloseBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionDeliverDoOutputBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionDeliveryRecordBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionExchangeBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionMembershipBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionQueueBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionQueuePositionBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionSessionStateBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionShadowReadyBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionTxAcceptBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionTxDequeueBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionTxEndBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionTxEnqueueBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionTxPublishBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterConnectionTxStartBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterDumpOfferBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterDumpRequestBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterReadyBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ClusterShutdownBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ConnectionCloseBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ConnectionCloseOkBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ConnectionHeartbeatBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ConnectionOpenBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ConnectionOpenOkBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ConnectionRedirectBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ConnectionSecureBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ConnectionSecureOkBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ConnectionStartBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ConnectionStartOkBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ConnectionTuneBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ConnectionTuneOkBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\constants.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\DeliveryProperties.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\DtxCommitBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\DtxEndBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\DtxForgetBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\DtxGetTimeoutBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\DtxGetTimeoutResult.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\DtxPrepareBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\DtxRecoverBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\DtxRecoverResult.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\DtxRollbackBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\DtxSelectBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\DtxSetTimeoutBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\DtxStartBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\enum.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ExchangeBindBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ExchangeBoundBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ExchangeBoundResult.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ExchangeDeclareBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ExchangeDeleteBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ExchangeQueryBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ExchangeQueryResult.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ExchangeUnbindBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ExecutionExceptionBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ExecutionResultBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ExecutionSyncBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FileAckBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FileCancelBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FileConsumeBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FileConsumeOkBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FileDeliverBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FileOpenBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FileOpenOkBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FileProperties.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FilePublishBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FileQosBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FileQosOkBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FileRejectBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FileReturnBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FileStageBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\FragmentProperties.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\frame_body_lists.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\Header.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageAcceptBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageAcquireBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageAcquireResult.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageCancelBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageFlowBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageFlushBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageProperties.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageRejectBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageReleaseBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageResumeBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageResumeResult.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageSetFlowModeBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageStopBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageSubscribeBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MessageTransferBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MethodBodyConstVisitor.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\MethodBodyDefaultVisitor.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\QueueDeclareBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\QueueDeleteBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\QueuePurgeBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\QueueQueryBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\QueueQueryResult.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\reply_exceptions.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ReplyTo.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\ServerInvoker.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\SessionAttachBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\SessionAttachedBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\SessionCommandPointBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\SessionCompletedBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\SessionConfirmedBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\SessionDetachBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\SessionDetachedBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\SessionExpectedBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\SessionFlushBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\SessionGapBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\SessionKnownCompletedBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\SessionRequestTimeoutBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\SessionTimeoutBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\StreamCancelBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\StreamConsumeBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\StreamConsumeOkBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\StreamDeliverBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\StreamProperties.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\StreamPublishBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\StreamQosBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\StreamQosOkBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\StreamReturnBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\TxCommitBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\TxRollbackBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\TxSelectBody.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\TypeCode.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\XaResult.h">
+ </File>
+ <File
+ RelativePath="gen\qpid\framing\Xid.h">
+ </File>
+ <File
+ RelativePath="qpid\Address.h">
+ </File>
+ <File
+ RelativePath="qpid\amqp_0_10\apply.h">
+ </File>
+ <File
+ RelativePath="qpid\amqp_0_10\Exception.h">
+ </File>
+ <File
+ RelativePath="qpid\amqp_0_10\SessionHandler.h">
+ </File>
+ <File
+ RelativePath="qpid\assert.h">
+ </File>
+ <File
+ RelativePath="qpid\DataDir.h">
+ </File>
+ <File
+ RelativePath="qpid\Exception.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\AccumulatedAck.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\AMQBody.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\AMQCommandControlBody.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\AMQContentBody.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\AMQDataBlock.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\AMQFrame.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\AMQHeaderBody.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\AMQHeartbeatBody.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\AMQMethodBody.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\amqp_framing.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\AMQP_HighestVersion.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\amqp_types.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\amqp_types_full.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\Array.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\Blob.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\BodyHandler.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\BodyHolder.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\Buffer.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\ChannelHandler.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\Endian.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\FieldTable.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\FieldValue.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\frame_functors.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\FrameDecoder.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\FrameDefaultVisitor.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\FrameHandler.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\FrameSet.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\Handler.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\HeaderProperties.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\InitiationHandler.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\InputHandler.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\Invoker.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\MaxMethodBodySize.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\MethodContent.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\ModelMethod.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\OutputHandler.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\ProtocolInitiation.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\ProtocolVersion.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\Proxy.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\SendContent.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\SequenceNumber.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\SequenceNumberSet.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\SequenceSet.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\StructHelper.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\TransferContent.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\TypeFilter.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\Uuid.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\variant.h qpid\log\Helpers.h">
+ </File>
+ <File
+ RelativePath="qpid\framing\Visitor.h">
+ </File>
+ <File
+ RelativePath="qpid\InlineAllocator.h">
+ </File>
+ <File
+ RelativePath="qpid\InlineVector.h">
+ </File>
+ <File
+ RelativePath="qpid\log\Logger.h">
+ </File>
+ <File
+ RelativePath="qpid\log\Options.h">
+ </File>
+ <File
+ RelativePath="qpid\log\OstreamOutput.h">
+ </File>
+ <File
+ RelativePath="qpid\log\Selector.h">
+ </File>
+ <File
+ RelativePath="qpid\log\SinkOptions.h">
+ </File>
+ <File
+ RelativePath="qpid\log\Statement.h">
+ </File>
+ <File
+ RelativePath="qpid\log\windows\SinkOptions.h">
+ </File>
+ <File
+ RelativePath="qpid\management\Manageable.h">
+ </File>
+ <File
+ RelativePath="qpid\management\ManagementObject.h">
+ </File>
+ <File
+ RelativePath="qpid\memory.h">
+ </File>
+ <File
+ RelativePath="qpid\Modules.h">
+ </File>
+ <File
+ RelativePath="qpid\Msg.h">
+ </File>
+ <File
+ RelativePath="qpid\Options.h">
+ </File>
+ <File
+ RelativePath="qpid\Plugin.h">
+ </File>
+ <File
+ RelativePath="qpid\pointer_to_other.h">
+ </File>
+ <File
+ RelativePath="qpid\ptr_map.h">
+ </File>
+ <File
+ RelativePath="qpid\RangeSet.h">
+ </File>
+ <File
+ RelativePath="qpid\RefCounted.h">
+ </File>
+ <File
+ RelativePath="qpid\RefCountedBuffer.h">
+ </File>
+ <File
+ RelativePath="qpid\Serializer.h">
+ </File>
+ <File
+ RelativePath="qpid\SessionId.h">
+ </File>
+ <File
+ RelativePath="qpid\SessionState.h">
+ </File>
+ <File
+ RelativePath="qpid\shared_ptr.h">
+ </File>
+ <File
+ RelativePath="qpid\SharedObject.h">
+ </File>
+ <File
+ RelativePath="qpid\StringUtils.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\AggregateOutput.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\AsynchIO.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\AsynchIOHandler.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\AtomicCount.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\AtomicValue.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\BlockingQueue.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\Condition.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\ConnectionCodec.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\ConnectionInputHandler.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\ConnectionInputHandlerFactory.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\ConnectionOutputHandler.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\ConnectionOutputHandlerPtr.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\CopyOnWriteArray.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\DeletionManager.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\Dispatcher.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\ExceptionHolder.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\FileSysDir.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\IntegerTypes.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\IOHandle.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\LockFile.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\LockPtr.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\Monitor.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\Mutex.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\OutputControl.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\OutputTask.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\PollableCondition.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\PollableQueue.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\Poller.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\ProtocolFactory.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\Runnable.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\ScopedIncrement.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\Semaphore.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\Shlib.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\ShutdownHandler.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\Socket.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\StateMonitor.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\StrError.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\SystemInfo.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\Thread.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\Time.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\TimeoutHandler.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\uuid.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\Waitable.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\windows\AsynchIoResult.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\windows\check.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\windows\Condition.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\windows\IntegerTypes.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\windows\IoHandlePrivate.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\windows\Mutex.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\windows\Time.h">
+ </File>
+ <File
+ RelativePath="qpid\sys\windows\uuid.h">
+ </File>
+ <File
+ RelativePath="qpid\Url.h">
+ </File>
+ <File
+ RelativePath="qpid\Version.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/RC9/qpid/cpp/src/generate.sh b/RC9/qpid/cpp/src/generate.sh
new file mode 100755
index 0000000000..581a45ff7f
--- /dev/null
+++ b/RC9/qpid/cpp/src/generate.sh
@@ -0,0 +1,67 @@
+# !/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Generate code from AMQP specification.
+# specs and gentools_dir are set by Makefile
+#
+set -e
+
+test -z "$JAVA" && JAVA=java ;
+test -z "$JAVAC" && JAVAC=javac ;
+
+srcdir=`dirname $0`
+checkspecs() {
+ for s in $specs; do test -f $s || return 1; done
+ return 0
+}
+
+# Can we generate code?
+if { test -d $gentools_dir && checkspecs &&
+ which $JAVA && which $JAVAC; } > /dev/null;
+then
+ echo "Generating code."
+ mkdir -p gen/qpid/framing
+ ( cd $gentools_dir/src && $JAVAC `find -name '*.java' -print` ; )
+ $JAVA -cp $gentools_dir/src org.apache.qpid.gentools.Main \
+ -c -o gen/qpid/framing -t $gentools_dir/templ.cpp $specs
+ GENERATED=yes
+fi
+
+# Print a Makefile variable assignment.
+make_assign() {
+ echo -n "$1 = "; shift
+ prefix=$1; shift
+ for f in $*; do echo "\\" ; echo -n " $prefix$f "; done
+ echo
+}
+
+# Generate a Makefile fragment
+(
+ make_assign "generated_cpp" "" `find gen -name '*.cpp' -print`
+ make_assign "generated_h" "" `find gen -name '*.h' -print`
+ if test x$GENERATED = xyes; then
+ make_assign "generator" "" $specs \
+ `find ../gentools \( -name '*.java' -o -name '*.tmpl' \) -print`
+ fi
+) > generate.mk-t
+mv generate.mk-t $srcdir/generate.mk
+
+
+
diff --git a/RC9/qpid/cpp/src/posix/QpiddBroker.cpp b/RC9/qpid/cpp/src/posix/QpiddBroker.cpp
new file mode 100644
index 0000000000..ba1ef640df
--- /dev/null
+++ b/RC9/qpid/cpp/src/posix/QpiddBroker.cpp
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpidd.h"
+#include "qpid/Exception.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/broker/Daemon.h"
+#include "qpid/broker/SignalHandler.h"
+#include "qpid/log/Logger.h"
+
+#include <iostream>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/utsname.h>
+
+using namespace std;
+using namespace qpid;
+using qpid::broker::Broker;
+using qpid::broker::Daemon;
+
+BootstrapOptions::BootstrapOptions(const char* argv0)
+ : qpid::Options("Options"),
+ common("", CONF_FILE),
+ module(MODULE_DIR),
+ log(argv0)
+{
+ add(common);
+ add(module);
+ add(log);
+}
+
+namespace {
+const std::string TCP = "tcp";
+}
+
+struct DaemonOptions : public qpid::Options {
+ bool daemon;
+ bool quit;
+ bool check;
+ int wait;
+ std::string piddir;
+ std::string transport;
+
+ DaemonOptions() : qpid::Options("Daemon options"), daemon(false), quit(false), check(false), wait(10), transport(TCP)
+ {
+ char *home = ::getenv("HOME");
+
+ if (home == 0)
+ piddir += "/tmp";
+ else
+ piddir += home;
+ piddir += "/.qpidd";
+
+ addOptions()
+ ("daemon,d", optValue(daemon), "Run as a daemon. Logs to syslog by default in this mode.")
+ ("transport", optValue(transport, "TRANSPORT"), "The transport for which to return the port")
+ ("pid-dir", optValue(piddir, "DIR"), "Directory where port-specific PID file is stored")
+ ("wait,w", optValue(wait, "SECONDS"), "Sets the maximum wait time to initialize the daemon. If the daemon fails to initialize, prints an error and returns 1")
+ ("check,c", optValue(check), "Prints the daemon's process ID to stdout and returns 0 if the daemon is running, otherwise returns 1")
+ ("quit,q", optValue(quit), "Tells the daemon to shut down");
+ }
+};
+
+struct QpiddPosixOptions : public QpiddOptionsPrivate {
+ DaemonOptions daemon;
+ QpiddOptions *parent;
+
+ QpiddPosixOptions(QpiddOptions *parent_) : parent(parent_) {
+ parent->add(daemon);
+ }
+};
+
+QpiddOptions::QpiddOptions(const char* argv0)
+ : qpid::Options("Options"),
+ common("", CONF_FILE),
+ module(MODULE_DIR),
+ log(argv0)
+{
+ add(common);
+ add(module);
+ add(broker);
+ add(log);
+
+ platform.reset(new QpiddPosixOptions(this));
+ qpid::Plugin::addOptions(*this);
+}
+
+void QpiddOptions::usage() const {
+ cout << "Usage: qpidd [OPTIONS]" << endl << endl << *this << endl;
+}
+
+struct QpiddDaemon : public Daemon {
+ QpiddPosixOptions *options;
+
+ QpiddDaemon(std::string pidDir, QpiddPosixOptions *opts)
+ : Daemon(pidDir), options(opts) {}
+
+ /** Code for parent process */
+ void parent() {
+ uint16_t port = wait(options->daemon.wait);
+ if (options->parent->broker.port == 0 || options->daemon.transport != TCP)
+ cout << port << endl;
+ }
+
+ /** Code for forked child process */
+ void child() {
+ boost::intrusive_ptr<Broker> brokerPtr(new Broker(options->parent->broker));
+ qpid::broker::SignalHandler::setBroker(brokerPtr);
+ uint16_t port=brokerPtr->getPort(options->daemon.transport);
+ ready(port); // Notify parent.
+ brokerPtr->run();
+ }
+};
+
+int QpiddBroker::execute (QpiddOptions *options) {
+ // Options that affect a running daemon.
+ QpiddPosixOptions *myOptions =
+ static_cast<QpiddPosixOptions *>(options->platform.get());
+ if (myOptions == 0)
+ throw Exception("Internal error obtaining platform options");
+
+ if (myOptions->daemon.check || myOptions->daemon.quit) {
+ pid_t pid = Daemon::getPid(myOptions->daemon.piddir,
+ options->broker.port);
+ if (pid < 0)
+ return 1;
+ if (myOptions->daemon.check)
+ cout << pid << endl;
+ if (myOptions->daemon.quit && kill(pid, SIGINT) < 0)
+ throw Exception("Failed to stop daemon: " + qpid::sys::strError(errno));
+ return 0;
+ }
+
+ // Starting the broker.
+ if (myOptions->daemon.daemon) {
+ // For daemon mode replace default stderr with syslog.
+ options->log.sinkOptions->detached();
+ qpid::log::Logger::instance().configure(options->log);
+ // Fork the daemon
+ QpiddDaemon d(myOptions->daemon.piddir, myOptions);
+ d.fork(); // Broker is stared in QpiddDaemon::child()
+ }
+ else { // Non-daemon broker.
+ boost::intrusive_ptr<Broker> brokerPtr(new Broker(options->broker));
+ broker::SignalHandler::setBroker(brokerPtr);
+ if (options->broker.port == 0 || myOptions->daemon.transport != TCP)
+ cout << uint16_t(brokerPtr->getPort(myOptions->daemon.transport)) << endl;
+ brokerPtr->run();
+ }
+ return 0;
+}
diff --git a/RC9/qpid/cpp/src/prof b/RC9/qpid/cpp/src/prof
new file mode 100755
index 0000000000..acfbaff2d4
--- /dev/null
+++ b/RC9/qpid/cpp/src/prof
@@ -0,0 +1,39 @@
+#!/bin/bash
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+
+
+rm /var/lib/oprofile/oprofiled.log
+
+opcontrol --reset
+opcontrol --setup --no-vmlinux --separate=library
+opcontrol --start
+# -- Do stuff here --
+./qpidd
+# -- End of stuff --
+opcontrol --stop
+opcontrol --dump
+opcontrol --shutdown
+opreport -l ./.libs/lt-qpidd > stats.txt
+opannotate --source --output-dir=qpidd-prof ./.libs/lt-qpidd
+
+# clear the relusts
+#opcontrol --reset
diff --git a/RC9/qpid/cpp/src/protocol_gen.mak b/RC9/qpid/cpp/src/protocol_gen.mak
new file mode 100644
index 0000000000..5c61eb90d5
--- /dev/null
+++ b/RC9/qpid/cpp/src/protocol_gen.mak
@@ -0,0 +1,28 @@
+# This nmake file generates the Qpid protocol files from the AMQP XML spec
+# and the management sources from the management XML specs.
+#
+# The Visual Studio projects assume the existence of the generated files.
+# The generated files are valid in Apache-released kits but must be generated
+# using this makefile for Windows developers working from the source
+# repository.
+
+specdir = ..\..\specs
+specs = $(specdir)\amqp.0-10-qpid-errata.xml ..\xml\cluster.xml
+
+rgen_dir=..\rubygen
+
+mgen_dir=..\managementgen
+mgmt_specs=$(specdir)\management-schema.xml \
+ .\qpid\acl\management-schema.xml \
+ .\qpid\cluster\management-schema.xml
+
+all: rubygen.mk gen\generate_MaxMethodBodySize_h.cpp managementgen.mk
+
+rubygen.mk gen\generate_MaxMethodBodySize_h.cpp: $(specs)
+ ruby -I $(rgen_dir) $(rgen_dir)\generate gen $(specs) all rubygen.mk
+
+# Management code generation... uses Python
+
+managementgen.mk: $(mgmt_specs)
+ python $(mgen_dir)\qmf-gen -m managementgen.mk -o gen\qmf $(mgmt_specs)
+
diff --git a/RC9/qpid/cpp/src/qmf.mk b/RC9/qpid/cpp/src/qmf.mk
new file mode 100644
index 0000000000..f97d10e06f
--- /dev/null
+++ b/RC9/qpid/cpp/src/qmf.mk
@@ -0,0 +1,35 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#
+# qmf agent library makefile fragment, to be included in Makefile.am
+#
+lib_LTLIBRARIES += libqmfagent.la
+
+module_hdr += \
+ qpid/agent/ManagementAgent.h \
+ qpid/agent/ManagementAgentImpl.h
+
+libqmfagent_la_SOURCES = \
+ qpid/agent/ManagementAgent.h \
+ qpid/agent/ManagementAgentImpl.cpp \
+ qpid/agent/ManagementAgentImpl.h
+
+libqmfagent_la_LIBADD = libqpidclient.la
+
diff --git a/RC9/qpid/cpp/src/qmfc.mk b/RC9/qpid/cpp/src/qmfc.mk
new file mode 100644
index 0000000000..46e8d82f35
--- /dev/null
+++ b/RC9/qpid/cpp/src/qmfc.mk
@@ -0,0 +1,65 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http:#www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#
+# qmf console library makefile fragment, to be included in Makefile.am
+#
+lib_LTLIBRARIES += libqmfconsole.la
+
+module_hdr += \
+ qpid/console/Agent.h \
+ qpid/console/Broker.h \
+ qpid/console/ClassKey.h \
+ qpid/console/ConsoleListener.h \
+ qpid/console/Event.h \
+ qpid/console/Object.h \
+ qpid/console/ObjectId.h \
+ qpid/console/Package.h \
+ qpid/console/Schema.h \
+ qpid/console/SequenceManager.h \
+ qpid/console/SessionManager.h \
+ qpid/console/Value.h
+
+libqmfconsole_la_SOURCES = \
+ qpid/console/Agent.h \
+ qpid/console/Agent.cpp \
+ qpid/console/Broker.h \
+ qpid/console/Broker.cpp \
+ qpid/console/ClassKey.h \
+ qpid/console/ClassKey.cpp \
+ qpid/console/ConsoleListener.h \
+ qpid/console/Event.h \
+ qpid/console/Event.cpp \
+ qpid/console/Object.h \
+ qpid/console/Object.cpp \
+ qpid/console/ObjectId.h \
+ qpid/console/ObjectId.cpp \
+ qpid/console/Package.h \
+ qpid/console/Package.cpp \
+ qpid/console/Schema.h \
+ qpid/console/Schema.cpp \
+ qpid/console/SequenceManager.h \
+ qpid/console/SequenceManager.cpp \
+ qpid/console/SessionManager.h \
+ qpid/console/SessionManager.cpp \
+ qpid/console/Value.h \
+ qpid/console/Value.cpp
+
+libqmfconsole_la_LIBADD = libqpidclient.la
+
diff --git a/RC9/qpid/cpp/src/qmfconsole.vcproj b/RC9/qpid/cpp/src/qmfconsole.vcproj
new file mode 100644
index 0000000000..a9dd414c0f
--- /dev/null
+++ b/RC9/qpid/cpp/src/qmfconsole.vcproj
@@ -0,0 +1,418 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="qmfconsole"
+ ProjectGUID="{C95DE177-FECA-1BAD-5EDC-8FFA4564ADCF}"
+ RootNamespace="qmfconsole"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Static_Debug\qmfconsole\I386"
+ ConfigurationType="4"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ PreprocessorDefinitions="_DEBUG;WIN32;_WINDOWS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800;4355"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile=".\qmfconsolesd.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Static_Release\qmfconsole\I386"
+ ConfigurationType="4"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN"
+ RuntimeLibrary="0"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800;4355"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile=".\qmfconsoles.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Static_Debug\qmfconsole\AMD64"
+ ConfigurationType="4"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ PreprocessorDefinitions="_DEBUG;WIN32;_WINDOWS;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800;4355"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile=".\qmfconsolesd.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Static_Release\qmfconsole\AMD64"
+ ConfigurationType="4"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN"
+ RuntimeLibrary="0"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800;4355"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,.,gen"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile=".\qmfconsoles.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;C;c">
+ <File
+ RelativePath="qpid\console\Agent.cpp">
+ </File>
+ <File
+ RelativePath="qpid\console\Broker.cpp">
+ </File>
+ <File
+ RelativePath="qpid\console\ClassKey.cpp">
+ </File>
+ <File
+ RelativePath="qpid\console\Object.cpp">
+ </File>
+ <File
+ RelativePath="qpid\console\ObjectId.cpp">
+ </File>
+ <File
+ RelativePath="qpid\console\Package.cpp">
+ </File>
+ <File
+ RelativePath="qpid\console\Schema.cpp">
+ </File>
+ <File
+ RelativePath="qpid\console\SequenceManager.cpp">
+ </File>
+ <File
+ RelativePath="qpid\console\SessionManager.cpp">
+ </File>
+ <File
+ RelativePath="qpid\console\Value.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hh">
+ <File
+ RelativePath="qpid\console\Agent.h">
+ </File>
+ <File
+ RelativePath="qpid\console\Broker.h">
+ </File>
+ <File
+ RelativePath="qpid\console\ClassKey.h">
+ </File>
+ <File
+ RelativePath="qpid\console\ConsoleListener.h">
+ </File>
+ <File
+ RelativePath="qpid\console\Event.h">
+ </File>
+ <File
+ RelativePath="qpid\console\Object.h">
+ </File>
+ <File
+ RelativePath="qpid\console\ObjectId.h">
+ </File>
+ <File
+ RelativePath="qpid\console\Package.h">
+ </File>
+ <File
+ RelativePath="qpid\console\Schema.h">
+ </File>
+ <File
+ RelativePath="qpid\console\SequenceManager.h">
+ </File>
+ <File
+ RelativePath="qpid\console\SessionManager.h">
+ </File>
+ <File
+ RelativePath="qpid\console\Value.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/RC9/qpid/cpp/src/qpid.sln b/RC9/qpid/cpp/src/qpid.sln
new file mode 100644
index 0000000000..8e886cf7a4
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid.sln
@@ -0,0 +1,72 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+# $Id: VC9WorkspaceCreator.pm 1439 2008-07-10 14:31:19Z elliott_c $
+#
+# This file was generated by MPC. Any changes made directly to
+# this file will be lost the next time it is generated.
+#
+# MPC Command:
+# C:\ace\MPC\mwc.pl -type vc9 -features boost=1 -static qpid.mwc
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MaxMethodBodySize", "MaxMethodBodySize.vcproj", "{CB5C939B-FECA-1BAD-BB9C-8C3A688E2823}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "broker", "broker.vcproj", "{09613D48-FECA-1BAD-9D20-8C37688E2823}"
+ ProjectSection(ProjectDependencies) = postProject
+ {C961EF23-FECA-1BAD-BB9C-8C3A688E2823} = {C961EF23-FECA-1BAD-BB9C-8C3A688E2823}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "client", "client.vcproj", "{6961DBA3-FECA-1BAD-F396-8C39688E2823}"
+ ProjectSection(ProjectDependencies) = postProject
+ {C961EF23-FECA-1BAD-BB9C-8C3A688E2823} = {C961EF23-FECA-1BAD-BB9C-8C3A688E2823}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "common.vcproj", "{C961EF23-FECA-1BAD-BB9C-8C3A688E2823}"
+ ProjectSection(ProjectDependencies) = postProject
+ {CB5C939B-FECA-1BAD-BB9C-8C3A688E2823} = {CB5C939B-FECA-1BAD-BB9C-8C3A688E2823}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {CB5C939B-FECA-1BAD-BB9C-8C3A688E2823}.Debug|Win32.ActiveCfg = Debug|Win32
+ {CB5C939B-FECA-1BAD-BB9C-8C3A688E2823}.Debug|Win32.Build.0 = Debug|Win32
+ {CB5C939B-FECA-1BAD-BB9C-8C3A688E2823}.Debug|x64.ActiveCfg = Debug|x64
+ {CB5C939B-FECA-1BAD-BB9C-8C3A688E2823}.Debug|x64.Build.0 = Debug|x64
+ {CB5C939B-FECA-1BAD-BB9C-8C3A688E2823}.Release|Win32.ActiveCfg = Release|Win32
+ {CB5C939B-FECA-1BAD-BB9C-8C3A688E2823}.Release|Win32.Build.0 = Release|Win32
+ {CB5C939B-FECA-1BAD-BB9C-8C3A688E2823}.Release|x64.ActiveCfg = Release|x64
+ {CB5C939B-FECA-1BAD-BB9C-8C3A688E2823}.Release|x64.Build.0 = Release|x64
+ {09613D48-FECA-1BAD-9D20-8C37688E2823}.Debug|Win32.ActiveCfg = Debug|Win32
+ {09613D48-FECA-1BAD-9D20-8C37688E2823}.Debug|Win32.Build.0 = Debug|Win32
+ {09613D48-FECA-1BAD-9D20-8C37688E2823}.Debug|x64.ActiveCfg = Debug|x64
+ {09613D48-FECA-1BAD-9D20-8C37688E2823}.Debug|x64.Build.0 = Debug|x64
+ {09613D48-FECA-1BAD-9D20-8C37688E2823}.Release|Win32.ActiveCfg = Release|Win32
+ {09613D48-FECA-1BAD-9D20-8C37688E2823}.Release|Win32.Build.0 = Release|Win32
+ {09613D48-FECA-1BAD-9D20-8C37688E2823}.Release|x64.ActiveCfg = Release|x64
+ {09613D48-FECA-1BAD-9D20-8C37688E2823}.Release|x64.Build.0 = Release|x64
+ {6961DBA3-FECA-1BAD-F396-8C39688E2823}.Debug|Win32.ActiveCfg = Debug|Win32
+ {6961DBA3-FECA-1BAD-F396-8C39688E2823}.Debug|Win32.Build.0 = Debug|Win32
+ {6961DBA3-FECA-1BAD-F396-8C39688E2823}.Debug|x64.ActiveCfg = Debug|x64
+ {6961DBA3-FECA-1BAD-F396-8C39688E2823}.Debug|x64.Build.0 = Debug|x64
+ {6961DBA3-FECA-1BAD-F396-8C39688E2823}.Release|Win32.ActiveCfg = Release|Win32
+ {6961DBA3-FECA-1BAD-F396-8C39688E2823}.Release|Win32.Build.0 = Release|Win32
+ {6961DBA3-FECA-1BAD-F396-8C39688E2823}.Release|x64.ActiveCfg = Release|x64
+ {6961DBA3-FECA-1BAD-F396-8C39688E2823}.Release|x64.Build.0 = Release|x64
+ {C961EF23-FECA-1BAD-BB9C-8C3A688E2823}.Debug|Win32.ActiveCfg = Debug|Win32
+ {C961EF23-FECA-1BAD-BB9C-8C3A688E2823}.Debug|Win32.Build.0 = Debug|Win32
+ {C961EF23-FECA-1BAD-BB9C-8C3A688E2823}.Debug|x64.ActiveCfg = Debug|x64
+ {C961EF23-FECA-1BAD-BB9C-8C3A688E2823}.Debug|x64.Build.0 = Debug|x64
+ {C961EF23-FECA-1BAD-BB9C-8C3A688E2823}.Release|Win32.ActiveCfg = Release|Win32
+ {C961EF23-FECA-1BAD-BB9C-8C3A688E2823}.Release|Win32.Build.0 = Release|Win32
+ {C961EF23-FECA-1BAD-BB9C-8C3A688E2823}.Release|x64.ActiveCfg = Release|x64
+ {C961EF23-FECA-1BAD-BB9C-8C3A688E2823}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/RC9/qpid/cpp/src/qpid/Address.cpp b/RC9/qpid/cpp/src/qpid/Address.cpp
new file mode 100644
index 0000000000..ac8c7f30b1
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/Address.cpp
@@ -0,0 +1,58 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "Address.h"
+
+#include <ostream>
+
+using namespace std;
+
+namespace qpid {
+
+TcpAddress::TcpAddress(const std::string& h, uint16_t p): host(h), port(p) {}
+
+struct AddressOstreamVisitor : public boost::static_visitor<ostream&> {
+ ostream& out;
+ AddressOstreamVisitor(ostream& o) : out(o) {}
+ template <class T> ostream& operator()(const T& data) { return out << data; }
+};
+
+ostream& operator<<(ostream& os, const Address& addr) {
+ AddressOstreamVisitor visitor(os);
+ return boost::apply_visitor(visitor, addr.value);
+}
+
+bool operator==(const TcpAddress& x, const TcpAddress& y) {
+ return y.host==x.host && y.port == x.port;
+}
+
+ostream& operator<<(ostream& os, const TcpAddress& a) {
+ return os << "tcp:" << a.host << ":" << a.port;
+}
+
+ExampleAddress::ExampleAddress(const char c) : data(c) {}
+
+bool operator==(const ExampleAddress& x, const ExampleAddress& y) {
+ return x.data == y.data;
+}
+
+ostream& operator<<(ostream& os, const ExampleAddress& ex) {
+ return os << "example:" << ex.data;
+}
+
+} // namespace qpid
diff --git a/RC9/qpid/cpp/src/qpid/Address.h b/RC9/qpid/cpp/src/qpid/Address.h
new file mode 100755
index 0000000000..9669985165
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/Address.h
@@ -0,0 +1,85 @@
+#ifndef QPID_ADDRESS_H
+#define QPID_ADDRESS_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/sys/IntegerTypes.h"
+
+#include <boost/variant.hpp>
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+namespace qpid {
+
+/** TCP address of a broker - host:port */
+struct TcpAddress {
+ static const uint16_t DEFAULT_PORT=5672;
+ explicit TcpAddress(const std::string& host_=std::string(),uint16_t port_=DEFAULT_PORT);
+ std::string host;
+ uint16_t port;
+};
+bool operator==(const TcpAddress& x, const TcpAddress& y);
+std::ostream& operator<<(std::ostream& os, const TcpAddress& a);
+
+/**@internal Not a real address type, this is a placeholder to
+ * demonstrate and validate multi-protocol Urls for unit tests and
+ * developer education only. An example address holds just a char.
+ */
+struct ExampleAddress {
+ explicit ExampleAddress(char data);
+ char data;
+};
+bool operator==(const ExampleAddress& x, const ExampleAddress& y);
+std::ostream& operator<<(std::ostream& os, const ExampleAddress& a);
+
+/**
+ * Contains the address of an AMQP broker. Can any supported type of
+ * broker address. Currently only TcpAddress is supported.
+ */
+struct Address {
+public:
+ Address(const Address& a) : value(a.value) {}
+ Address(const TcpAddress& tcp) : value(tcp) {}
+ Address(const ExampleAddress& eg) : value(eg) {} ///<@internal
+
+ template <class AddressType> Address& operator=(const AddressType& t) { value=t; return *this; }
+
+ /** Get the address of type AddressType.
+ *@return AddressType* pointing to the contained address or 0 if
+ *contained address is not of type AddressType.
+ */
+ template <class AddressType> AddressType* get() { return boost::get<AddressType>(&value); }
+
+ /** Get the address of type AddressType.
+ *@return AddressType* pointing to the contained address or 0 if
+ *contained address is not of type AddressType.
+ */
+ template <class AddressType> const AddressType* get() const { return boost::get<AddressType>(&value); }
+
+private:
+ boost::variant<TcpAddress,ExampleAddress> value;
+ friend std::ostream& operator<<(std::ostream& os, const Address& addr);
+};
+
+
+
+} // namespace qpid
+
+#endif /*!QPID_ADDRESS_H*/
diff --git a/RC9/qpid/cpp/src/qpid/DataDir.cpp b/RC9/qpid/cpp/src/qpid/DataDir.cpp
new file mode 100644
index 0000000000..4d61d22219
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/DataDir.cpp
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Exception.h"
+#include "DataDir.h"
+#include "qpid/log/Statement.h"
+#include "qpid/sys/FileSysDir.h"
+
+namespace qpid {
+
+DataDir::DataDir (std::string path) :
+ enabled (!path.empty ()),
+ dirPath (path)
+{
+ if (!enabled)
+ {
+ QPID_LOG (info, "No data directory - Disabling persistent configuration");
+ return;
+ }
+
+ sys::FileSysDir dir(dirPath);
+ if (!dir.exists())
+ dir.mkdir();
+ std::string lockFileName(path);
+ lockFileName += "/lock";
+ lockFile = std::auto_ptr<sys::LockFile>(new sys::LockFile(lockFileName, true));
+}
+
+DataDir::~DataDir () {}
+
+} // namespace qpid
+
diff --git a/RC9/qpid/cpp/src/qpid/DataDir.h b/RC9/qpid/cpp/src/qpid/DataDir.h
new file mode 100644
index 0000000000..6b45d8747b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/DataDir.h
@@ -0,0 +1,50 @@
+#ifndef QPID_DATADIR_H
+#define QPID_DATADIR_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <string>
+#include <memory>
+#include "qpid/sys/LockFile.h"
+
+namespace qpid {
+
+/**
+ * DataDir class.
+ */
+class DataDir
+{
+ const bool enabled;
+ const std::string dirPath;
+ std::auto_ptr<qpid::sys::LockFile> lockFile;
+
+ public:
+
+ DataDir (std::string path);
+ ~DataDir ();
+
+ bool isEnabled() { return enabled; }
+ const std::string& getPath() { return dirPath; }
+};
+
+} // namespace qpid
+
+#endif /*!QPID_DATADIR_H*/
diff --git a/RC9/qpid/cpp/src/qpid/Exception.cpp b/RC9/qpid/cpp/src/qpid/Exception.cpp
new file mode 100644
index 0000000000..05d1a26f57
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/Exception.cpp
@@ -0,0 +1,55 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/log/Statement.h"
+#include "Exception.h"
+#include <typeinfo>
+#include <assert.h>
+#include <string.h>
+
+namespace qpid {
+
+Exception::Exception(const std::string& msg) throw() : message(msg) {
+ QPID_LOG_IF(debug, !msg.empty(), "Exception constructed: " << message);
+}
+
+Exception::~Exception() throw() {}
+
+std::string Exception::getPrefix() const { return ""; }
+
+std::string Exception::getMessage() const { return message; }
+
+const char* Exception::what() const throw() {
+ // Construct the what string the first time it is needed.
+ if (whatStr.empty()) {
+ whatStr = getPrefix();
+ if (!whatStr.empty()) whatStr += ": ";
+ whatStr += message;
+ }
+ return whatStr.c_str();
+}
+
+ClosedException::ClosedException(const std::string& msg)
+ : Exception(msg) {}
+
+std::string ClosedException::getPrefix() const { return "Closed"; }
+
+} // namespace qpid
diff --git a/RC9/qpid/cpp/src/qpid/Exception.h b/RC9/qpid/cpp/src/qpid/Exception.h
new file mode 100644
index 0000000000..86bf8fbc4a
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/Exception.h
@@ -0,0 +1,93 @@
+#ifndef _Exception_
+#define _Exception_
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/framing/amqp_types.h"
+#include "qpid/framing/constants.h"
+#include "qpid/framing/enum.h"
+#include "qpid/sys/StrError.h"
+#include "qpid/Msg.h"
+
+#include <memory>
+#include <string>
+#include <errno.h>
+
+namespace qpid
+{
+
+/**
+ * Base class for Qpid runtime exceptions.
+ */
+class Exception : public std::exception
+{
+ public:
+ explicit Exception(const std::string& message=std::string()) throw();
+ virtual ~Exception() throw();
+ virtual const char* what() const throw(); // prefix: message
+ virtual std::string getMessage() const; // Unprefixed message
+ virtual std::string getPrefix() const; // Prefix
+
+ private:
+ std::string message;
+ mutable std::string whatStr;
+};
+
+/** Exception that includes an errno message. */
+struct ErrnoException : public Exception {
+ ErrnoException(const std::string& msg, int err) : Exception(msg+": "+qpid::sys::strError(err)) {}
+ ErrnoException(const std::string& msg) : Exception(msg+": "+qpid::sys::strError(errno)) {}
+};
+
+struct SessionException : public Exception {
+ const framing::execution::ErrorCode code;
+ SessionException(framing::execution::ErrorCode code_, const std::string& message)
+ : Exception(message), code(code_) {}
+};
+
+struct ChannelException : public Exception {
+ const framing::session::DetachCode code;
+ ChannelException(framing::session::DetachCode _code, const std::string& message)
+ : Exception(message), code(_code) {}
+};
+
+struct ConnectionException : public Exception {
+ const framing::connection::CloseCode code;
+ ConnectionException(framing::connection::CloseCode _code, const std::string& message)
+ : Exception(message), code(_code) {}
+};
+
+struct ClosedException : public Exception {
+ ClosedException(const std::string& msg=std::string());
+ std::string getPrefix() const;
+};
+
+/**
+ * Exception representing transport failure
+ */
+struct TransportFailure : public Exception {
+ TransportFailure(const std::string& msg=std::string()) : Exception(msg) {}
+};
+
+} // namespace qpid
+
+#endif /*!_Exception_*/
diff --git a/RC9/qpid/cpp/src/qpid/InlineAllocator.h b/RC9/qpid/cpp/src/qpid/InlineAllocator.h
new file mode 100644
index 0000000000..bf2f570599
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/InlineAllocator.h
@@ -0,0 +1,84 @@
+#ifndef QPID_INLINEALLOCATOR_H
+#define QPID_INLINEALLOCATOR_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <memory>
+#include <assert.h>
+#include <boost/type_traits/type_with_alignment.hpp>
+#include <boost/type_traits/alignment_of.hpp>
+
+namespace qpid {
+
+/**
+ * An allocator that has inline storage for up to Max objects
+ * of type BaseAllocator::value_type.
+ */
+template <class BaseAllocator, size_t Max>
+class InlineAllocator : public BaseAllocator {
+ public:
+ typedef typename BaseAllocator::pointer pointer;
+ typedef typename BaseAllocator::size_type size_type;
+ typedef typename BaseAllocator::value_type value_type;
+
+ InlineAllocator() : allocated(false) {}
+ InlineAllocator(const InlineAllocator& x) : BaseAllocator(x), allocated(false) {}
+
+ pointer allocate(size_type n) {
+ if (n <= Max && !allocated) {
+ allocated=true;
+ return reinterpret_cast<value_type*>(address());
+ }
+ else
+ return BaseAllocator::allocate(n, 0);
+ }
+
+ void deallocate(pointer p, size_type n) {
+ if (p == address()) {
+ assert(allocated);
+ allocated=false;
+ }
+ else
+ BaseAllocator::deallocate(p, n);
+ }
+
+ template<typename T1>
+ struct rebind {
+ typedef typename BaseAllocator::template rebind<T1>::other BaseOther;
+ typedef InlineAllocator<BaseOther, Max> other;
+ };
+
+ private:
+ // POD object with alignment and size to hold Max value_types.
+ static const size_t ALIGNMENT=boost::alignment_of<value_type>::value;
+ typedef typename boost::type_with_alignment<ALIGNMENT>::type Aligner;
+ union Store {
+ Aligner aligner_;
+ char sizer_[sizeof(value_type)*Max];
+ } store;
+ value_type* address() { return reinterpret_cast<value_type*>(&store); }
+ bool allocated;
+};
+
+} // namespace qpid
+
+#endif /*!QPID_INLINEALLOCATOR_H*/
diff --git a/RC9/qpid/cpp/src/qpid/InlineVector.h b/RC9/qpid/cpp/src/qpid/InlineVector.h
new file mode 100644
index 0000000000..551b9912e7
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/InlineVector.h
@@ -0,0 +1,68 @@
+#ifndef QPID_INLINEVECTOR_H
+#define QPID_INLINEVECTOR_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "InlineAllocator.h"
+#include <vector>
+
+namespace qpid {
+
+/**
+ * A vector that stores up to Max elements in inline storage,
+ * otherwise uses normal vector allocation.
+ *
+ * NOTE: depends on some non-standard but highly probably assumptions
+ * about how std::vector uses its allocator, they are true for g++.
+ * - default constructor does not allocate.
+ * - reserve(N) does not allocate more than N elements.
+ * - vector never re-allocates when size() < capacity()
+ */
+template <class T, size_t Max, class Alloc=std::allocator<T> >
+class InlineVector : public std::vector<T, InlineAllocator<Alloc, Max> >
+{
+ typedef std::vector<T, InlineAllocator<Alloc, Max> > Base;
+ public:
+ typedef typename Base::allocator_type allocator_type;
+ typedef typename Base::value_type value_type;
+ typedef typename Base::size_type size_type;
+
+ explicit InlineVector(const allocator_type& a=allocator_type()) : Base(a) {
+ this->reserve(Max);
+ }
+
+ explicit InlineVector(size_type n, const value_type& x = value_type(),
+ const allocator_type& a=allocator_type()) : Base(a)
+ {
+ this->reserve(std::max(n, Max));
+ this->insert(this->end(), n, x);
+ }
+
+ InlineVector(const InlineVector& x) : Base() {
+ this->reserve(std::max(x.size(), Max));
+ *this = x;
+ }
+};
+
+} // namespace qpid
+
+#endif /*!QPID_INLINEVECTOR_H*/
diff --git a/RC9/qpid/cpp/src/qpid/Modules.cpp b/RC9/qpid/cpp/src/qpid/Modules.cpp
new file mode 100644
index 0000000000..1b802f0019
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/Modules.cpp
@@ -0,0 +1,78 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Modules.h"
+#include "Exception.h"
+#include "qpid/log/Statement.h"
+#include "qpid/sys/Shlib.h"
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+
+namespace fs=boost::filesystem;
+
+namespace qpid {
+
+ModuleOptions::ModuleOptions(const std::string& defaultModuleDir)
+ : qpid::Options("Module options"), loadDir(defaultModuleDir), noLoad(false)
+{
+ addOptions()
+ ("module-dir", optValue(loadDir, "DIR"), "Load all shareable modules in this directory")
+ ("load-module", optValue(load, "FILE"), "Specifies additional module(s) to be loaded")
+ ("no-module-dir", optValue(noLoad), "Don't load modules from module directory");
+}
+
+void tryShlib(const char* libname, bool noThrow) {
+ try {
+ sys::Shlib shlib(libname);
+ QPID_LOG (info, "Loaded Module: " << libname);
+ }
+ catch (const std::exception& /*e*/) {
+ if (!noThrow)
+ throw;
+ }
+}
+
+void loadModuleDir (std::string dirname, bool isDefault)
+{
+ fs::path dirPath (dirname, fs::native);
+
+ if (!fs::exists (dirPath))
+ {
+ if (isDefault)
+ return;
+ throw Exception ("Directory not found: " + dirname);
+ }
+ if (!fs::is_directory(dirPath))
+ {
+ throw Exception ("Invalid value for module-dir: " + dirname + " is not a directory");
+ }
+
+ fs::directory_iterator endItr;
+ for (fs::directory_iterator itr (dirPath); itr != endItr; ++itr)
+ {
+ if (!fs::is_directory(*itr) &&
+ itr->string().find (".so") == itr->string().length() - 3)
+ tryShlib (itr->string().data(), true);
+ }
+}
+
+} // namespace qpid
diff --git a/RC9/qpid/cpp/src/qpid/Modules.h b/RC9/qpid/cpp/src/qpid/Modules.h
new file mode 100644
index 0000000000..2a3b24f359
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/Modules.h
@@ -0,0 +1,43 @@
+#ifndef QPID_MODULES_H
+#define QPID_MODULES_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Options.h"
+#include <string>
+#include <vector>
+
+namespace qpid {
+
+struct ModuleOptions : public qpid::Options {
+ std::string loadDir;
+ std::vector<std::string> load;
+ bool noLoad;
+ ModuleOptions(const std::string& defaultModuleDir);
+};
+
+void tryShlib(const char* libname, bool noThrow);
+void loadModuleDir (std::string dirname, bool isDefault);
+
+} // namespace qpid
+
+#endif /*!QPID_MODULES_H*/
diff --git a/RC9/qpid/cpp/src/qpid/Msg.h b/RC9/qpid/cpp/src/qpid/Msg.h
new file mode 100644
index 0000000000..7214db611f
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/Msg.h
@@ -0,0 +1,61 @@
+#ifndef QPID_MSG_H
+#define QPID_MSG_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <sstream>
+#include <iostream>
+
+namespace qpid {
+
+/** A simple wrapper for std::ostringstream that allows
+ * in place construction of a message and automatic conversion
+ * to string.
+ * E.g.
+ *@code
+ * void foo(const std::string&);
+ * foo(Msg() << "hello " << 32);
+ *@endcode
+ * Will construct the string "hello 32" and pass it to foo()
+ */
+struct Msg {
+ std::ostringstream os;
+ Msg() {}
+ Msg(const Msg& m) : os(m.str()) {}
+ std::string str() const { return os.str(); }
+ operator std::string() const { return str(); }
+};
+
+template <class T> const Msg& operator<<(const Msg& m, const T& t) {
+ const_cast<std::ostringstream&>(m.os)<<t; return m;
+}
+
+inline std::ostream& operator<<(std::ostream& o, const Msg& m) {
+ return o<<m.str();
+}
+
+/** Construct a message using operator << and append (file:line) */
+#define QPID_MSG(message) ::qpid::Msg() << message << " (" << __FILE__ << ":" << __LINE__ << ")"
+
+} // namespace qpid
+
+#endif /*!QPID_MSG_H*/
diff --git a/RC9/qpid/cpp/src/qpid/Options.cpp b/RC9/qpid/cpp/src/qpid/Options.cpp
new file mode 100644
index 0000000000..e521b1220a
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/Options.cpp
@@ -0,0 +1,468 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "Options.h"
+#include "qpid/Exception.h"
+
+#include <boost/bind.hpp>
+
+#include <fstream>
+#include <algorithm>
+#include <iostream>
+
+namespace qpid {
+
+using namespace std;
+
+
+/*
+ * ---------------------------------------------
+ * Explanation for Boost 103200 conditional code
+ * ---------------------------------------------
+ *
+ * Please see large comment in Options.h .
+ *
+ */
+
+#if ( BOOST_VERSION == 103200 )
+std::vector<std::string> Options::long_names;
+std::vector<std::string> Options::short_names;
+#endif
+
+
+
+
+namespace {
+
+struct EnvOptMapper {
+ static bool matchChar(char env, char opt) {
+ return (env==toupper(opt)) || (strchr("-.", opt) && env=='_');
+ }
+
+ static bool matchStr(const string& env, boost::shared_ptr<po::option_description> desc) {
+ return std::equal(env.begin(), env.end(), desc->long_name().begin(), &matchChar);
+ }
+
+ static bool matchCase(const string& env, boost::shared_ptr<po::option_description> desc) {
+ return env == desc->long_name();
+ }
+
+ EnvOptMapper(const Options& o) : opts(o) {}
+
+ string operator()(const string& envVar) {
+ static const std::string prefix("QPID_");
+ if (envVar.substr(0, prefix.size()) == prefix) {
+ string env = envVar.substr(prefix.size());
+#if (BOOST_VERSION >= 103300)
+ typedef const std::vector< boost::shared_ptr<po::option_description> > OptDescs;
+ OptDescs::const_iterator i =
+ find_if(opts.options().begin(), opts.options().end(), boost::bind(matchStr, env, _1));
+ if (i != opts.options().end())
+ return (*i)->long_name();
+#else
+ /*
+ * For Boost version 103200 and below.
+ *
+ * In Boost version 103200, the options_description::options member,
+ * used above, is private. So what I will do here is use the
+ * count() funtion, which returns a 1 or 0 indicating presence or
+ * absence of the environment variable.
+ *
+ * If it is present, I will return its name. Env vars do not have
+ * short and long forms, so the name is synonymous with the long
+ * name. (This would not work for command line args.)
+ * And if it's absent -- an empty string.
+ */
+
+
+ /*
+ * The env vars come in unaltered, i.e. QPID_FOO, but the
+ * options are stored normalized as "qpid-foo". Change the
+ * local variable "env" so it can be found by "opts".
+ */
+ for (std::string::iterator i = env.begin(); i != env.end(); ++i)
+ {
+ *i = (*i == '_')
+ ? '-'
+ : ::tolower(*i);
+ }
+
+ if ( opts.count(env.c_str()) > 0 )
+ {
+ return env.c_str();
+ }
+ else
+ {
+ return string();
+ }
+#endif
+ }
+ return string();
+ }
+
+
+ bool
+ isComment ( string const & str )
+ {
+ size_t i = str.find_first_not_of ( " \t" );
+
+ if ( i == string::npos )
+ return true;
+
+ return str[i] == '#';
+ }
+
+
+ string configFileLine (string& line) {
+
+ if ( isComment ( line ) )
+ return string();
+
+ size_t pos = line.find ('=');
+ if (pos == string::npos)
+ return string();
+ string key = line.substr (0, pos);
+#if (BOOST_VERSION >= 103300)
+ typedef const std::vector< boost::shared_ptr<po::option_description> > OptDescs;
+ OptDescs::const_iterator i =
+ find_if(opts.options().begin(), opts.options().end(), boost::bind(matchCase, key, _1));
+ if (i != opts.options().end())
+ return string (line) + "\n";
+ else
+ return string();
+#else
+ // Use 'count' to see if this option exists. Using 'find' will SEGV or hang
+ // if the option has not been defined yet.
+ if ( opts.count(key.c_str()) > 0 )
+ return string ( line ) + "\n";
+ else
+ return string ( );
+#endif
+ }
+
+ const Options& opts;
+};
+
+}
+std::string prettyArg(const std::string& name, const std::string& value) {
+ return value.empty() ? name+" " : name+" ("+value+") ";
+}
+
+Options::Options(const string& name) :
+ po::options_description(name)
+
+#if ( BOOST_VERSION == 103200 )
+ , m_less_easy(this, this)
+#endif
+{
+}
+
+
+
+
+
+void Options::parse(int argc, char const* const* argv, const std::string& configFile, bool allowUnknown)
+{
+ string defaultConfigFile = configFile; // May be changed by env/cmdline
+ string parsing;
+ try {
+ po::variables_map vm;
+ parsing="command line options";
+ if (argc > 0 && argv != 0) {
+ if (allowUnknown) {
+#if (BOOST_VERSION >= 103300)
+ // This hideous workaround is required because boost 1.33 has a bug
+ // that causes 'allow_unregistered' to not work.
+ po::command_line_parser clp = po::command_line_parser(argc, const_cast<char**>(argv)).
+ options(*this).allow_unregistered();
+ po::parsed_options opts = clp.run();
+ po::parsed_options filtopts = clp.run();
+ filtopts.options.clear ();
+ for (std::vector< po::basic_option<char> >::iterator i = opts.options.begin();
+ i != opts.options.end(); i++)
+ if (!i->unregistered)
+ filtopts.options.push_back (*i);
+ po::store(filtopts, vm);
+
+#elif ( BOOST_VERSION == 103200 )
+
+ /*
+ * "Tokenize" the argv to get rid of equals signs.
+ */
+ vector<string> tokenized_argv;
+ vector<string>::iterator iter;
+
+ for ( int i = 0; i < argc; ++ i )
+ {
+ string s = argv[i];
+ size_t equals_pos = s.find_first_of ( '=' );
+
+ if ( string::npos == equals_pos ) // There's no equals sign. This is a token.
+ {
+ tokenized_argv.push_back(s);
+ }
+ else
+ {
+ // Two tokens -- before and after the equals position.
+ tokenized_argv.push_back ( s.substr(0, equals_pos) );
+ tokenized_argv.push_back ( s.substr(equals_pos+1) );
+ }
+ }
+
+
+ /*
+ * Now "filter" the tokenized argv, to get rid of all
+ * unrecognized options. Because Boost 103200 has no
+ * facility for dealing gracefully with "unregistered"
+ * options.
+ */
+ vector<string> filtered_argv;
+ vector<string>::iterator the_end = tokenized_argv.end();
+
+ // The program-name gets in for free...
+ iter = tokenized_argv.begin();
+ filtered_argv.push_back ( * iter );
+ ++ iter;
+
+ // ...but all other args get checked.
+ while ( iter < the_end )
+ {
+ /*
+ * If this is an argument that is registered,
+ * copy it to filtered_argv and also copy all
+ * of its arguments.
+ */
+ if ( is_registered_option ( * iter ) )
+ {
+ // Store this recognized arg.
+ filtered_argv.push_back ( * iter );
+ ++ iter;
+
+ // Copy all values for the above arg.
+ // Args are tokens that do not start with a minus.
+ while ( (iter < the_end) && ((* iter)[0] != '-') )
+ {
+ filtered_argv.push_back ( * iter );
+ ++ iter;
+ }
+ }
+ else
+ {
+ // Skip this unrecognized arg.
+ ++ iter;
+
+ // Copy all values for the above arg.
+ // Values are tokens that do not start with a minus.
+ while ( (iter < the_end) && ( '-' != (*iter)[0] ) )
+ {
+ ++ iter;
+ }
+ }
+ }
+
+ // Make an array of temporary C strings, because
+ // the interface I can use wants it that way.
+ int new_argc = filtered_argv.size();
+ char ** new_argv = new char * [ new_argc ];
+ int i = 0;
+
+ // cout << "NEW ARGV: |";
+ for ( iter = filtered_argv.begin();
+ iter < filtered_argv.end();
+ ++ iter, ++ i
+ )
+ {
+ new_argv[i] = strdup( (* iter).c_str() );
+ // cout << " " << new_argv[i] ;
+ }
+ // cout << "|\n";
+
+
+ // Use the array of C strings.
+ po::basic_parsed_options<char> bpo = po::parse_command_line(new_argc, const_cast<char**>(new_argv), *this);
+ po::store(bpo, vm);
+
+
+ // Now free the temporary C strings.
+ for ( i = 0; i < new_argc; ++ i )
+ {
+ free ( new_argv[i] );
+ }
+ delete[] new_argv;
+
+#endif
+ }
+ else
+ po::store(po::parse_command_line(argc, const_cast<char**>(argv), *this), vm);
+ }
+ parsing="environment variables";
+ po::store(po::parse_environment(*this, EnvOptMapper(*this)), vm);
+ po::notify(vm); // configFile may be updated from arg/env options.
+ if (!configFile.empty()) {
+ parsing="configuration file "+configFile;
+ ifstream conf(configFile.c_str());
+ if (conf.good()) {
+ // Remove this hack when we get a stable version of boost that
+ // can allow unregistered options in config files.
+ EnvOptMapper mapper(*this);
+ stringstream filtered;
+
+ while (!conf.eof()) {
+ string line;
+ getline (conf, line);
+ filtered << mapper.configFileLine (line);
+ }
+
+ po::store(po::parse_config_file(filtered, *this), vm);
+ // End of hack
+ }
+ else {
+ // No error if default configfile is missing/unreadable
+ // but complain for non-default config file.
+ if (configFile != defaultConfigFile)
+ throw Exception("cannot read configuration file "
+ +configFile);
+ }
+ }
+ po::notify(vm);
+ }
+ catch (const std::exception& e) {
+ ostringstream msg;
+ msg << "Error in " << parsing << ": " << e.what() << endl;
+#if (BOOST_VERSION >= 103300)
+ if (find_nothrow("help", false))
+ msg << "Use --help to see valid options" << endl;
+#endif
+ throw Exception(msg.str());
+ }
+}
+
+CommonOptions::CommonOptions(const string& name, const string& configfile)
+ : Options(name), config(configfile)
+{
+ addOptions()
+ ("help,h", optValue(help), "Displays the help message")
+ ("version,v", optValue(version), "Displays version information")
+ ("config", optValue(config, "FILE"), "Reads configuration from FILE");
+}
+
+
+
+
+#if ( BOOST_VERSION == 103200 )
+options_description_less_easy_init&
+options_description_less_easy_init::operator()(char const * name,
+ char const * description)
+{
+ // Snoop on the arguments....
+ owner->register_names ( name );
+ // ... then call parent function explicitly.
+ po::options_description_easy_init::operator() ( name, description );
+ return * this;
+}
+
+
+options_description_less_easy_init&
+options_description_less_easy_init::operator()(char const * name,
+ const po::value_semantic* s)
+{
+ // Snoop on the arguments....
+ owner->register_names ( name );
+ // ... then call parent function explicitly.
+ po::options_description_easy_init::operator() ( name, s );
+ return * this;
+}
+
+
+options_description_less_easy_init&
+options_description_less_easy_init::operator()(const char* name,
+ const po::value_semantic* s,
+ const char* description)
+{
+ // Snoop on the arguments....
+ owner->register_names ( name );
+ // ... then call parent function explicitly.
+ po::options_description_easy_init::operator() ( name, s, description );
+ return * this;
+}
+
+
+
+
+
+void
+Options::register_names ( std::string s )
+{
+
+ std::string::size_type comma_pos = s.find_first_of ( ',' );
+
+ if ( std::string::npos == comma_pos )
+ {
+ // There is no short-name.
+ long_names.push_back ( s );
+ }
+ else
+ {
+ std::string long_name = s.substr(0, comma_pos),
+ short_name = s.substr(comma_pos+1);
+ long_names .push_back ( long_name );
+ short_names.push_back ( short_name );
+ }
+
+ /*
+ * There is no way to tell when the adding of new options is finished,
+ * so I re-sort after each one.
+ */
+ std::sort ( long_names .begin(), long_names .end() );
+ std::sort ( short_names.begin(), short_names.end() );
+}
+
+
+
+
+
+bool
+Options::is_registered_option ( std::string s )
+{
+ std::string without_dashes = s.substr ( s.find_first_not_of ( '-' ) );
+ std::vector<std::string>::iterator i;
+
+ // Look among the long names.
+ i = std::find ( long_names.begin(),
+ long_names.end(),
+ without_dashes
+ );
+ if ( i != long_names.end() )
+ return true;
+
+ // Look among the short names.
+ i = std::find ( short_names.begin(),
+ short_names.end(),
+ without_dashes
+ );
+ if ( i != short_names.end() )
+ return true;
+
+
+ return false;
+}
+#endif
+
+
+} // namespace qpid
+
diff --git a/RC9/qpid/cpp/src/qpid/Options.h b/RC9/qpid/cpp/src/qpid/Options.h
new file mode 100644
index 0000000000..cb86d27241
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/Options.h
@@ -0,0 +1,257 @@
+#ifndef QPID_COMMONOPTIONS_H
+#define QPID_COMMONOPTIONS_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/Exception.h"
+#include <boost/program_options.hpp>
+#include <boost/format.hpp>
+#include <sstream>
+#include <iterator>
+#include <algorithm>
+#include <string>
+
+
+namespace qpid {
+namespace po=boost::program_options;
+
+
+
+///@internal
+std::string prettyArg(const std::string&, const std::string&);
+
+/** @internal Normally only constructed by optValue() */
+template <class T>
+class OptionValue : public po::typed_value<T> {
+ public:
+ OptionValue(T& value, const std::string& arg)
+ : po::typed_value<T>(&value), argName(arg) {}
+ std::string name() const { return argName; }
+
+ private:
+ std::string argName;
+};
+
+
+/** Create an option value.
+ * name, value appear after the option name in help like this:
+ * <name> (=<value>)
+ * T must support operator <<.
+ *@see Options for example of use.
+ */
+template<class T>
+po::value_semantic* optValue(T& value, const char* name) {
+ std::string valstr(boost::lexical_cast<std::string>(value));
+ return new OptionValue<T>(value, prettyArg(name, valstr));
+}
+
+/** Create a vector value. Multiple occurences of the option are
+ * accumulated into the vector
+ */
+template <class T>
+po::value_semantic* optValue(std::vector<T>& value, const char* name) {
+ using namespace std;
+ ostringstream os;
+ copy(value.begin(), value.end(), ostream_iterator<T>(os, " "));
+ string val=os.str();
+ if (!val.empty())
+ val.erase(val.end()-1); // Remove trailing " "
+ return (new OptionValue<vector<T> >(value, prettyArg(name, val)));
+}
+
+/** Create a boolean switch value. Presence of the option sets the value. */
+inline po::value_semantic* optValue(bool& value) { return po::bool_switch(&value); }
+
+/**
+ * Base class for options.
+ * Example of use:
+ @code
+ struct MySubOptions : public Options {
+ int x;
+ string y;
+ MySubOptions() : Options("Sub options") {
+ addOptions()
+ ("x", optValue(x,"XUNIT"), "Option X")
+ ("y", optValue(y, "YUNIT"), "Option Y");
+ }
+ };
+
+ struct MyOptions : public Options {
+ bool z;
+ vector<string> foo;
+ MySubOptions subOptions;
+ MyOptions() : Options("My Options") {
+ addOptions()
+ ("z", boolSwitch(z), "Option Z")
+ ("foo", optValue(foo), "Multiple option foo");
+ add(subOptions);
+ }
+
+ main(int argc, char** argv) {
+ Options opts;
+ opts.parse(argc, char** argv);
+ // Use values
+ dosomething(opts.subOptions.x);
+ if (error)
+ cout << opts << end; // Help message.
+ }
+
+ @endcode
+ */
+
+
+
+
+/*
+ * ---------------------------------------------
+ * Explanation for Boost 103200 conditional code
+ * ---------------------------------------------
+ *
+ * This boost version has an implementation of the program_options library
+ * that has no provision for allowing unregistered options to pass by.
+ *
+ * But that means that, if you have a program that loads optional modules
+ * after start-up, and those modules each have their own set of options,
+ * then if you parse the command line too soon, you will get spurious
+ * reports of unrecognized options -- and the program will exit!
+ *
+ * And we must process the command-line before module-loading, because we
+ * need to look at the "bootstrap" options.
+ *
+ * This conditional code:
+ *
+ * 1. implements it's own functor class, derived from the Boost
+ * "options_description_easy_init" class. This functor is used
+ * to process added options and do the functor chaining, so that
+ * I can snoop on the arguments before doing an explicit call
+ * to its parent.
+ *
+ * 2. It implements two static vectors, one to hold long names, and
+ * one for short names, so that options declared by modules are
+ * not forgotten when their options_description goes out of scope.
+ *
+ * I will be thrilled to personally delete this code if we ever decide
+ * that qpid doesn't really need to support this antique version of Boost.
+ *
+ */
+
+#if ( BOOST_VERSION == 103200 )
+struct Options;
+
+
+struct
+options_description_less_easy_init
+ : public po::options_description_easy_init
+{
+ options_description_less_easy_init ( Options * my_owner,
+ po::options_description * my_parents_owner
+ )
+ : po::options_description_easy_init(my_parents_owner)
+ {
+ owner = my_owner;
+ }
+
+
+ options_description_less_easy_init&
+ operator()(char const * name,
+ char const * description);
+
+
+ options_description_less_easy_init&
+ operator()(char const * name,
+ const po::value_semantic* s);
+
+
+ options_description_less_easy_init&
+ operator()(const char* name,
+ const po::value_semantic* s,
+ const char* description);
+
+
+ Options * owner;
+};
+#endif
+
+
+
+
+
+
+struct Options : public po::options_description {
+
+ struct Exception : public qpid::Exception {
+ Exception(const std::string& msg) : qpid::Exception(msg) {}
+ };
+
+ Options(const std::string& name=std::string());
+
+ /**
+ * Parses options from argc/argv, environment variables and config file.
+ * Note the filename argument can reference an options variable that
+ * is updated by argc/argv or environment variable parsing.
+ */
+ void parse(int argc, char const* const* argv,
+ const std::string& configfile=std::string(),
+ bool allowUnknown = false);
+
+
+ #if ( BOOST_VERSION == 103200 )
+ options_description_less_easy_init m_less_easy;
+
+ options_description_less_easy_init addOptions() {
+ return m_less_easy;
+ }
+
+ bool
+ is_registered_option ( std::string s );
+
+ void
+ register_names ( std::string s );
+
+ static std::vector<std::string> long_names;
+ static std::vector<std::string> short_names;
+ #else
+ boost::program_options::options_description_easy_init addOptions() {
+ return add_options();
+ }
+ #endif
+};
+
+
+
+/**
+ * Standard options for configuration
+ */
+struct CommonOptions : public Options {
+ CommonOptions(const std::string& name=std::string(),
+ const std::string& configfile=std::string());
+ bool help;
+ bool version;
+ std::string config;
+};
+
+
+
+
+} // namespace qpid
+
+#endif /*!QPID_COMMONOPTIONS_H*/
diff --git a/RC9/qpid/cpp/src/qpid/Plugin.cpp b/RC9/qpid/cpp/src/qpid/Plugin.cpp
new file mode 100644
index 0000000000..e4b76db28a
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/Plugin.cpp
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Plugin.h"
+#include "qpid/Options.h"
+#include <boost/bind.hpp>
+#include <algorithm>
+
+namespace qpid {
+
+namespace {
+
+Plugin::Plugins& thePlugins() {
+ // This is a single threaded singleton implementation so
+ // it is important to be sure that the first use of this
+ // singleton is when the program is still single threaded
+ static Plugin::Plugins plugins;
+ return plugins;
+}
+
+void invoke(boost::function<void()> f) { f(); }
+
+} // namespace
+
+Plugin::Target::~Target() { finalize(); }
+
+void Plugin::Target::finalize() {
+ for_each(finalizers.begin(), finalizers.end(), invoke);
+ finalizers.clear();
+}
+
+void Plugin::Target::addFinalizer(const boost::function<void()>& f) {
+ finalizers.push_back(f);
+}
+
+Plugin::Plugin() {
+ // Register myself.
+ thePlugins().push_back(this);
+}
+
+Plugin::~Plugin() {}
+
+Options* Plugin::getOptions() { return 0; }
+
+const Plugin::Plugins& Plugin::getPlugins() { return thePlugins(); }
+
+namespace {
+template <class F> void each_plugin(const F& f) {
+ std::for_each(Plugin::getPlugins().begin(), Plugin::getPlugins().end(), f);
+}
+}
+
+void Plugin::addOptions(Options& opts) {
+ for (Plugins::const_iterator i = getPlugins().begin(); i != getPlugins().end(); ++i) {
+ if ((*i)->getOptions())
+ opts.add(*(*i)->getOptions());
+ }
+}
+
+void Plugin::earlyInitAll(Target& t) { each_plugin(boost::bind(&Plugin::earlyInitialize, _1, boost::ref(t))); }
+void Plugin::initializeAll(Target& t) { each_plugin(boost::bind(&Plugin::initialize, _1, boost::ref(t))); }
+
+} // namespace qpid
diff --git a/RC9/qpid/cpp/src/qpid/Plugin.h b/RC9/qpid/cpp/src/qpid/Plugin.h
new file mode 100644
index 0000000000..50d8e01227
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/Plugin.h
@@ -0,0 +1,118 @@
+#ifndef QPID_PLUGIN_H
+#define QPID_PLUGIN_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <boost/noncopyable.hpp>
+#include <boost/function.hpp>
+#include <vector>
+
+/**@file Generic plug-in framework. */
+
+namespace qpid {
+struct Options;
+
+/**
+ * Plug-in base class.
+ */
+class Plugin : private boost::noncopyable {
+ public:
+ typedef std::vector<Plugin*> Plugins;
+
+ /**
+ * Base interface for targets that can receive plug-ins.
+ * Also allows plug-ins to attach a a function to be called
+ * when the target is 'finalized'.
+ */
+ class Target : private boost::noncopyable
+ {
+ public:
+ /** Calls finalize() if not already called. */
+ virtual ~Target();
+
+ /** Run all the finalizers */
+ void finalize();
+
+ /** Add a function to run when finalize() is called */
+ void addFinalizer(const boost::function<void()>&);
+
+ private:
+ std::vector<boost::function<void()> > finalizers;
+ };
+
+ /**
+ * Constructor registers the plug-in to appear in getPlugins().
+ *
+ * A concrete Plugin is instantiated as a global or static
+ * member variable in a library so it is registered during
+ * initialization when the library is loaded.
+ */
+ Plugin();
+
+ virtual ~Plugin();
+
+ /**
+ * Configuration options for the plugin.
+ * Then will be updated during option parsing by the host program.
+ *
+ * @return An options group or 0 for no options. Default returns 0.
+ * Plugin retains ownership of return value.
+ */
+ virtual Options* getOptions();
+
+ /**
+ * Initialize Plugin functionality on a Target, called before
+ * initializing the target.
+ *
+ * Plugins should ignore targets they don't recognize.
+ *
+ * Called before the target itself is initialized.
+ */
+ virtual void earlyInitialize(Target&) = 0;
+
+ /**
+ * Initialize Plugin functionality on a Target. Called after
+ * initializing the target.
+ *
+ * Plugins should ignore targets they don't recognize.
+ *
+ * Called after the target is fully initialized.
+ */
+ virtual void initialize(Target&) = 0;
+
+ /** List of registered Plugin objects.
+ * Caller must not delete plugin pointers.
+ */
+ static const Plugins& getPlugins();
+
+ /** Call earlyInitialize() on all registered plugins */
+ static void earlyInitAll(Target&);
+
+ /** Call initialize() on all registered plugins */
+ static void initializeAll(Target&);
+
+ /** For each registered plugin, add plugin.getOptions() to opts. */
+ static void addOptions(Options& opts);
+};
+
+} // namespace qpid
+
+#endif /*!QPID_PLUGIN_H*/
diff --git a/RC9/qpid/cpp/src/qpid/RangeSet.h b/RC9/qpid/cpp/src/qpid/RangeSet.h
new file mode 100644
index 0000000000..1ba4fbbcef
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/RangeSet.h
@@ -0,0 +1,330 @@
+#ifndef QPID_RANGESET_H
+#define QPID_RANGESET_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/InlineVector.h"
+#include <boost/iterator/iterator_facade.hpp>
+#include <boost/operators.hpp>
+#include <boost/bind.hpp>
+#include <algorithm>
+#include <numeric>
+
+namespace qpid {
+
+/** A range of values, used in RangeSet.
+ * Range(begin, end) includes begin but excludes end.
+ * Range::makeClosed(first,last) includes both first and last.
+ */
+template <class T>
+class Range {
+ public:
+ static Range makeClosed(const T& first, T last) { return Range(first, ++last); }
+
+ Range() : begin_(), end_() {}
+ explicit Range(const T& t) : begin_(t), end_(t) { ++end_; }
+ Range(const T& b, const T& e) : begin_(b), end_(e) { assert(b <= e); }
+
+ T begin() const { return begin_; }
+ /** End of _open_ range, i.e. !contains(end()) */
+ T end() const { return end_; }
+
+ T first() const { assert(!empty()); return begin_; }
+ /** Last in closed range, i.e. contains(end()) */
+ T last() const { assert(!empty()); T ret=end_; return --ret; }
+
+ void begin(const T& t) { begin_ = t; }
+ void end(const T& t) { end_ = t; }
+ size_t size() const { return end_ - begin_; }
+ bool empty() const { return begin_ == end_; }
+
+ bool contains(const T& x) const { return begin_ <= x && x < end_; }
+ bool contains(const Range& r) const { return begin_ <= r.begin_ && r.end_ <= end_; }
+ bool strictContains(const Range& r) const { return begin_ < r.begin_ && r.end_ < end_; }
+
+ bool operator==(const Range& x) { return begin_ == x.begin_ && end_== x.end_; }
+
+ bool operator<(const T& t) const { return end_ < t; }
+ bool operator<(const Range<T>& r) const { return end_ < r.begin_; }
+
+ /** touching ranges can be merged into a single range. */
+ bool touching(const Range& r) const {
+ return std::max(begin_, r.begin_) <= std::min(end_, r.end_);
+ }
+
+ /** @pre touching */
+ void merge(const Range& r) {
+ assert(touching(r));
+ begin_ = std::min(begin_, r.begin_);
+ end_ = std::max(end_, r.end_);
+ }
+
+ operator bool() const { return !empty(); }
+
+ template <class S> void serialize(S& s) { s(begin_)(end_); }
+
+ private:
+ T begin_, end_;
+};
+
+
+/**
+ * A set implemented as a list of [begin, end) ranges.
+ * T must be LessThanComparable and Incrementable.
+ * RangeSet only provides const iterators.
+ */
+template <class T>
+class RangeSet
+ : boost::additive1<RangeSet<T>,
+ boost::additive2<RangeSet<T>, Range<T>,
+ boost::additive2<RangeSet<T>, T> > >
+{
+ typedef InlineVector<Range<T>, 3> Ranges; // TODO aconway 2008-04-21: what's the optimial inlined value?
+
+ public:
+
+ class iterator : public boost::iterator_facade<
+ iterator,
+ const T,
+ boost::forward_traversal_tag>
+ {
+ public:
+ iterator() : ranges(), iter(), value() {}
+
+ private:
+ typedef typename Ranges::const_iterator RangesIter;
+ iterator(const Ranges& r, const RangesIter& i, const T& t)
+ : ranges(&r), iter(i), value(t) {}
+
+ void increment();
+ bool equal(const iterator& i) const;
+ const T& dereference() const { return value; }
+
+ const Ranges* ranges;
+ RangesIter iter;
+ T value;
+
+ friend class RangeSet<T>;
+ friend class boost::iterator_core_access;
+ };
+
+ typedef iterator const_iterator;
+
+ RangeSet() {}
+ explicit RangeSet(const Range<T>& r) { *this += r; }
+ RangeSet(const T& a, const T& b) { *this += Range<T>(a,b); }
+
+ bool contiguous() const { return ranges.size() <= 1; }
+
+ bool contains(const T& t) const;
+ bool contains(const Range<T>&) const;
+
+ /**@pre contiguous() */
+ Range<T> toRange() const;
+
+ bool operator==(const RangeSet<T>&) const;
+
+ void addRange (const Range<T>&);
+ void addSet (const RangeSet<T>&);
+
+ RangeSet<T>& operator+=(const T& t) { return *this += Range<T>(t); }
+ RangeSet<T>& operator+=(const Range<T>& r) { addRange(r); return *this; }
+ RangeSet<T>& operator+=(const RangeSet<T>& s) { addSet(s); return *this; }
+
+ void removeRange (const Range<T>&);
+ void removeSet (const RangeSet<T>&);
+
+ RangeSet<T>& operator-=(const T& t) { return *this -= Range<T>(t); }
+ RangeSet<T>& operator-=(const Range<T>& r) { removeRange(r); return *this; }
+ RangeSet<T>& operator-=(const RangeSet<T>& s) { removeSet(s); return *this; }
+
+ T front() const { return ranges.front().begin(); }
+ T back() const { return ranges.back().end(); }
+
+ // Iterate over elements in the set.
+ iterator begin() const;
+ iterator end() const;
+
+ // Iterate over ranges in the set.
+ typedef typename Ranges::const_iterator RangeIterator;
+ RangeIterator rangesBegin() const { return ranges.begin(); }
+ RangeIterator rangesEnd() const { return ranges.end(); }
+ size_t rangesSize() const { return ranges.size(); }
+
+ // The difference between the start and end of this range set
+ uint32_t span() const;
+
+ size_t size() const;
+ bool empty() const { return ranges.empty(); }
+ void clear() { ranges.clear(); }
+
+ /** Return the largest contiguous range containing x.
+ * Returns the empty range [x,x) if x is not in the set.
+ */
+ Range<T> rangeContaining(const T&) const;
+
+ template <class S> void serialize(S& s) { s.split(*this); s(ranges.begin(), ranges.end()); }
+ template <class S> void encode(S& s) const { s(uint16_t(ranges.size()*sizeof(Range<T>))); }
+ template <class S> void decode(S& s) { uint16_t sz; s(sz); ranges.resize(sz/sizeof(Range<T>)); }
+
+ private:
+ static size_t accumulateSize(size_t s, const Range<T>& r) { return s+r.size(); }
+ Ranges ranges;
+
+ template <class U> friend std::ostream& operator<<(std::ostream& o, const RangeSet<U>& r);
+
+ friend class iterator;
+};
+
+template <class T>
+std::ostream& operator<<(std::ostream& o, const Range<T>& r) {
+ return o << "[" << r.begin() << "," << r.end() << ")";
+}
+
+template <class T>
+std::ostream& operator<<(std::ostream& o, const RangeSet<T>& rs) {
+ std::ostream_iterator<Range<T> > i(o, " ");
+ o << "{ ";
+ std::copy(rs.ranges.begin(), rs.ranges.end(), i);
+ return o << "}";
+}
+
+template <class T>
+bool RangeSet<T>::contains(const T& t) const {
+ typename Ranges::const_iterator i =
+ std::lower_bound(ranges.begin(), ranges.end(), Range<T>(t));
+ return i != ranges.end() && i->contains(t);
+}
+
+template <class T>
+bool RangeSet<T>::contains(const Range<T>& r) const {
+ typename Ranges::const_iterator i =
+ std::lower_bound(ranges.begin(), ranges.end(), r);
+ return i != ranges.end() && i->contains(r);
+}
+
+template <class T> void RangeSet<T>::addRange(const Range<T>& r) {
+ if (r.empty()) return;
+ typename Ranges::iterator i =
+ std::lower_bound(ranges.begin(), ranges.end(), r);
+ if (i == ranges.end() || !i->touching(r))
+ ranges.insert(i, r);
+ else {
+ i->merge(r);
+ typename Ranges::iterator j = i;
+ if (++j != ranges.end() && i->touching(*j)) {
+ i->merge(*j);
+ ranges.erase(j);
+ }
+ }
+}
+
+
+template <class T> void RangeSet<T>::addSet(const RangeSet<T>& s) {
+ typedef RangeSet<T>& (RangeSet<T>::*RangeSetRangeOp)(const Range<T>&);
+ std::for_each(s.ranges.begin(), s.ranges.end(),
+ boost::bind((RangeSetRangeOp)&RangeSet<T>::operator+=, this, _1));
+}
+
+template <class T> void RangeSet<T>::removeRange(const Range<T>& r) {
+ if (r.empty()) return;
+ typename Ranges::iterator i,j;
+ i = std::lower_bound(ranges.begin(), ranges.end(), r);
+ if (i == ranges.end() || i->begin() >= r.end())
+ return; // Outside of set
+ if (*i == r) // Erase i
+ ranges.erase(i);
+ else if (i->strictContains(r)) { // Split i
+ Range<T> i1(i->begin(), r.begin());
+ Range<T> i2(r.end(), i->end());
+ *i = i2;
+ ranges.insert(i, i1);
+ } else {
+ if (i->begin() < r.begin()) { // Truncate i
+ i->end(r.begin());
+ ++i;
+ }
+ for (j = i; j != ranges.end() && r.contains(*j); ++j)
+ ; // Ranges to erase.
+ if (j != ranges.end() && j->end() > r.end())
+ j->begin(r.end()); // Truncate j
+ ranges.erase(i,j);
+ }
+}
+
+template <class T> void RangeSet<T>::removeSet(const RangeSet<T>& r) {
+ std::for_each(
+ r.ranges.begin(), r.ranges.end(),
+ boost::bind(&RangeSet<T>::removeRange, this, _1));
+}
+
+template <class T> Range<T> RangeSet<T>::toRange() const {
+ assert(contiguous());
+ return empty() ? Range<T>() : ranges.front();
+}
+
+template <class T> void RangeSet<T>::iterator::increment() {
+ assert(ranges && iter != ranges->end());
+ if (!iter->contains(++value)) {
+ ++iter;
+ if (iter == ranges->end())
+ *this=iterator(); // end() iterator
+ else
+ value=iter->begin();
+ }
+}
+
+template <class T> bool RangeSet<T>::operator==(const RangeSet<T>& r) const {
+ return ranges.size() == r.ranges.size() && std::equal(ranges.begin(), ranges.end(), r.ranges.begin());
+}
+
+template <class T> typename RangeSet<T>::iterator RangeSet<T>::begin() const {
+ return empty() ? end() : iterator(ranges, ranges.begin(), front());
+}
+
+template <class T> typename RangeSet<T>::iterator RangeSet<T>::end() const {
+ return iterator();
+}
+
+template <class T> bool RangeSet<T>::iterator::equal(const iterator& i) const {
+ return ranges==i.ranges && (ranges==0 || value==i.value);
+}
+
+template <class T> Range<T> RangeSet<T>::rangeContaining(const T& t) const {
+ typename Ranges::const_iterator i =
+ std::lower_bound(ranges.begin(), ranges.end(), Range<T>(t));
+ return (i != ranges.end() && i->contains(t)) ? *i : Range<T>(t,t);
+}
+
+template <class T> uint32_t RangeSet<T>::span() const {
+ if (ranges.empty()) return 0;
+ return ranges.back().last() - ranges.front().first();
+}
+
+template <class T> size_t RangeSet<T>::size() const {
+ return std::accumulate(rangesBegin(), rangesEnd(), 0, &RangeSet<T>::accumulateSize);
+}
+
+} // namespace qpid
+
+
+#endif /*!QPID_RANGESET_H*/
diff --git a/RC9/qpid/cpp/src/qpid/RefCounted.h b/RC9/qpid/cpp/src/qpid/RefCounted.h
new file mode 100644
index 0000000000..10b5e4afcc
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/RefCounted.h
@@ -0,0 +1,59 @@
+#ifndef QPID_REFCOUNTED_H
+#define QPID_REFCOUNTED_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <boost/utility.hpp>
+#include <boost/detail/atomic_count.hpp>
+
+namespace qpid {
+
+/**
+ * Reference-counted base class.
+ * Note: this class isn't copyable - you must copy the intrusive_ptr that points
+ * to the class that has mixed this in not the class itself (as that would sidestep
+ * the reference counting)
+ */
+class RefCounted : boost::noncopyable {
+ mutable boost::detail::atomic_count count;
+
+public:
+ RefCounted() : count(0) {}
+ void addRef() const { ++count; }
+ void release() const { if (--count==0) delete this; }
+ long refCount() { return count; }
+
+protected:
+ virtual ~RefCounted() {};
+};
+
+
+} // namespace qpid
+
+// intrusive_ptr support.
+namespace boost {
+inline void intrusive_ptr_add_ref(const qpid::RefCounted* p) { p->addRef(); }
+inline void intrusive_ptr_release(const qpid::RefCounted* p) { p->release(); }
+}
+
+
+#endif /*!QPID_REFCOUNTED_H*/
diff --git a/RC9/qpid/cpp/src/qpid/RefCountedBuffer.cpp b/RC9/qpid/cpp/src/qpid/RefCountedBuffer.cpp
new file mode 100644
index 0000000000..57ef48ac42
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/RefCountedBuffer.cpp
@@ -0,0 +1,53 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "RefCountedBuffer.h"
+#include <new>
+
+namespace qpid {
+
+RefCountedBuffer::RefCountedBuffer() : count(0) {}
+
+void RefCountedBuffer::destroy() const {
+ this->~RefCountedBuffer();
+ ::delete[] reinterpret_cast<const char*>(this);
+}
+
+char* RefCountedBuffer::addr() const {
+ return const_cast<char*>(reinterpret_cast<const char*>(this)+sizeof(RefCountedBuffer));
+}
+
+RefCountedBuffer::pointer RefCountedBuffer::create(size_t n) {
+ char* store=::new char[n+sizeof(RefCountedBuffer)];
+ new(store) RefCountedBuffer;
+ return pointer(reinterpret_cast<RefCountedBuffer*>(store));
+}
+
+RefCountedBuffer::pointer::pointer() {}
+RefCountedBuffer::pointer::pointer(RefCountedBuffer* x) : p(x) {}
+RefCountedBuffer::pointer::pointer(const pointer& x) : p(x.p) {}
+RefCountedBuffer::pointer::~pointer() {}
+RefCountedBuffer::pointer& RefCountedBuffer::pointer::operator=(const RefCountedBuffer::pointer& x) { p = x.p; return *this; }
+
+char* RefCountedBuffer::pointer::cp() const { return p ? p->get() : 0; }
+} // namespace qpid
+
+
diff --git a/RC9/qpid/cpp/src/qpid/RefCountedBuffer.h b/RC9/qpid/cpp/src/qpid/RefCountedBuffer.h
new file mode 100644
index 0000000000..c332325378
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/RefCountedBuffer.h
@@ -0,0 +1,89 @@
+#ifndef QPID_REFCOUNTEDBUFFER_H
+#define QPID_REFCOUNTEDBUFFER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <boost/utility.hpp>
+#include <boost/detail/atomic_count.hpp>
+#include <boost/intrusive_ptr.hpp>
+
+namespace qpid {
+// FIXME aconway 2008-09-06: easy to add alignment
+/**
+ * Reference-counted byte buffer.
+ * No alignment guarantees.
+ */
+class RefCountedBuffer : boost::noncopyable {
+ mutable boost::detail::atomic_count count;
+ RefCountedBuffer();
+ void destroy() const;
+ char* addr() const;
+
+public:
+ /** Smart char pointer to a reference counted buffer */
+ class pointer {
+ boost::intrusive_ptr<RefCountedBuffer> p;
+ char* cp() const;
+ pointer(RefCountedBuffer* x);
+ friend class RefCountedBuffer;
+
+ public:
+ pointer();
+ pointer(const pointer&);
+ ~pointer();
+ pointer& operator=(const pointer&);
+
+ char* get() { return cp(); }
+ operator char*() { return cp(); }
+ char& operator*() { return *cp(); }
+ char& operator[](size_t i) { return cp()[i]; }
+
+ const char* get() const { return cp(); }
+ operator const char*() const { return cp(); }
+ const char& operator*() const { return *cp(); }
+ const char& operator[](size_t i) const { return cp()[i]; }
+ };
+
+ /** Create a reference counted buffer of size n */
+ static pointer create(size_t n);
+
+ /** Get a pointer to the start of the buffer. */
+ char* get() { return addr(); }
+ const char* get() const { return addr(); }
+ char& operator[](size_t i) { return get()[i]; }
+ const char& operator[](size_t i) const { return get()[i]; }
+
+ void addRef() const { ++count; }
+ void release() const { if (--count==0) destroy(); }
+ long refCount() { return count; }
+};
+
+} // namespace qpid
+
+// intrusive_ptr support.
+namespace boost {
+inline void intrusive_ptr_add_ref(const qpid::RefCountedBuffer* p) { p->addRef(); }
+inline void intrusive_ptr_release(const qpid::RefCountedBuffer* p) { p->release(); }
+}
+
+
+#endif /*!QPID_REFCOUNTEDBUFFER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/Serializer.h b/RC9/qpid/cpp/src/qpid/Serializer.h
new file mode 100644
index 0000000000..a8ded9f5e0
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/Serializer.h
@@ -0,0 +1,197 @@
+#ifndef QPID_SERIALIZER_H
+#define QPID_SERIALIZER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <limits>
+#include <algorithm>
+#include "qpid/Exception.h" // FIXME aconway 2008-04-03: proper exception class.
+
+namespace qpid {
+
+/**
+ * Overload for types that do not provide a serialize() member.
+ * It should retrun a wrapper holding a reference to t that implements
+ * serialize()
+ */
+template <class T> T& serializable(T& t) { return t; }
+
+/** Serialize std::pair */
+template <class T, class U> struct SerializablePair {
+ std::pair<T,U>& value;
+ SerializablePair(std::pair<T,U>& x) : value(x) {}
+ template <class S> void serialize(S& s) { s(value.first)(value.second); }
+};
+
+template <class T, class U>
+SerializablePair<T,U> serializable(std::pair<T,U>& p) {
+ return SerializablePair<T,U>(p);
+}
+
+/**
+ * Base class for all serializers.
+ * Derived serializers inherit from either Encoder or Decoder.
+ * Serializers can be used as functors or static_visitors.
+ */
+template <class Derived> class Serializer {
+ public:
+ /** Temporarily set a lower relative limit on the serializer */
+ class ScopedLimit {
+ public:
+ ScopedLimit(Serializer& s, size_t l)
+ : serializer(s), save(serializer.setLimit(l)) {}
+
+ ~ScopedLimit() { serializer.setAbsLimit(save); }
+
+ private:
+ Serializer& serializer;
+ size_t save;
+ };
+
+ static size_t maxLimit() { return std::numeric_limits<size_t>::max(); }
+
+ Serializer() : bytes(0), limit(maxLimit()) {}
+
+ typedef Derived& result_type; // unary functor requirement.
+
+ /** Wrapper functor to pass serializer functors by reference. */
+ template <class S> struct Ref {
+ typedef typename S::result_type result_type;
+ S& s;
+ Ref(S& ss) : s(ss) {}
+ template <class T> result_type operator()(T& x) { return s(x); }
+ template <class T> result_type operator()(const T& x) { return s(x); }
+ };
+
+ /** Reference wrapper to pass serializers by reference,
+ * e.g. to std:: functions that take functors.
+ */
+ template <class S> static Ref<S> ref(S& s) { return Ref<S>(s); }
+
+ /** Generic rule to serialize an iterator range */
+ template <class Iter> Derived& operator()(Iter begin, Iter end) {
+ std::for_each(begin, end, ref(this->self()));
+ return self();
+ }
+
+ /** Set limit relative to current position.
+ * @return old absolute limit.
+ */
+ size_t setLimit(size_t n) {
+ size_t l=limit;
+ limit = bytes+n;
+ return l;
+ }
+
+ /** Get the max number of bytes that can be processed under the
+ * current limit.
+ */
+ size_t bytesRemaining() const {
+ return limit - bytes;
+ }
+ /** Set absolute limit. */
+ void setAbsLimit(size_t n) {
+ limit = n;
+ if (bytes > limit)
+ throw Exception("Framing error: data overrun"); // FIXME aconway 2008-04-03: proper exception.
+ }
+
+ protected:
+ Derived& self() { return *static_cast<Derived*>(this); }
+ void addBytes(size_t n) {
+ size_t newBytes=bytes+n;
+ if (newBytes > limit)
+ throw Exception("Framing error: data overrun"); // FIXME aconway 2008-04-03: proper exception.
+ bytes = newBytes;
+ }
+
+ private:
+ void checkLimit() {
+ }
+
+ size_t bytes; // how many bytes serialized.
+ size_t limit; // bytes may not exceed this limit.
+};
+
+/**
+ * Base class for encoders, provides generic encode functions.
+ *
+ * A derived encoder must provide operator(const T&) to encode all
+ * primitive types T.
+ */
+template <class Derived> class EncoderBase : public Serializer<Derived> {
+ public:
+ using Serializer<Derived>::operator();
+ using Serializer<Derived>::self;
+
+ /** Default op() for non-primitive types. */
+ template <class T> Derived& operator()(const T& t) {
+ serializable(const_cast<T&>(t)).serialize(self()); return self();
+ }
+
+ /** Split serialize() into encode()/decode() */
+ template <class T> Derived& split(const T& t) {
+ t.encode(self()); return self();
+ }
+};
+
+/**
+ * Base class for decoders, provides generic decode functions.
+ *
+ * A derived encoder must provide operator(T&) to encode all
+ * primitive types T.
+ */
+template <class Derived> class DecoderBase : public Serializer<Derived> {
+ public:
+ using Serializer<Derived>::operator();
+ using Serializer<Derived>::self;
+
+ /** Default op() for non-primitive types. */
+ template <class T> Derived& operator()(T& t) {
+
+ serializable(t).serialize(self()); return self();
+ }
+
+ /** Split serialize() into encode()/decode() */
+ template <class T> Derived& split(T& t) {
+ t.decode(self()); return self();
+ }
+};
+
+/** Serialize a type by converting it to/from another type.
+ * To serialize type Foo by converting to/from type Bar create
+ * a serializable() overload like this:
+ *
+ * SerializeAs<Foo,Bar> serializable(Foo& t) { return SerializeAs<Foo,Bar>(t); }
+ */
+template <class Type, class AsType>
+struct SerializeAs {
+ Type& value;
+ SerializeAs(Type & t) : value(t) {}
+ template <class S> void serialize(S& s) { s.split(*this); }
+ template <class S> void encode(S& s) const { s(AsType(value)); }
+ template <class S> void decode(S& s) { AsType x; s(x); value=Type(x); }
+};
+
+} // namespace qpid
+
+#endif /*!QPID_SERIALIZER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/SessionId.cpp b/RC9/qpid/cpp/src/qpid/SessionId.cpp
new file mode 100644
index 0000000000..fce6619f5d
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/SessionId.cpp
@@ -0,0 +1,47 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "SessionId.h"
+#include <sstream>
+
+namespace qpid {
+
+SessionId::SessionId(const std::string& u, const std::string& n) : userId(u), name(n) {}
+
+bool SessionId::operator<(const SessionId& id) const {
+ return userId < id.userId || (userId == id.userId && name < id.name);
+}
+
+bool SessionId::operator==(const SessionId& id) const {
+ return id.name == name && id.userId == userId;
+}
+
+std::ostream& operator<<(std::ostream& o, const SessionId& id) {
+ return o << id.getName() << "@" << id.getUserId();
+}
+
+std::string SessionId::str() const {
+ std::ostringstream o;
+ o << *this;
+ return o.str();
+}
+
+} // namespace qpid
diff --git a/RC9/qpid/cpp/src/qpid/SessionId.h b/RC9/qpid/cpp/src/qpid/SessionId.h
new file mode 100644
index 0000000000..291c42a2bb
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/SessionId.h
@@ -0,0 +1,59 @@
+#ifndef QPID_SESSIONID_H
+#define QPID_SESSIONID_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <boost/operators.hpp>
+#include <string>
+
+namespace qpid {
+
+/** Identifier for a session.
+ * There are two parts to a session identifier:
+ *
+ * getUserId() returns the authentication principal associated with
+ * the session's connection.
+ *
+ * getName() returns the session name.
+ *
+ * The name must be unique among sessions with the same authentication
+ * principal.
+ */
+class SessionId : boost::totally_ordered1<SessionId> {
+ std::string userId;
+ std::string name;
+ public:
+ SessionId(const std::string& userId=std::string(), const std::string& name=std::string());
+ std::string getUserId() const { return userId; }
+ std::string getName() const { return name; }
+ bool operator<(const SessionId&) const ;
+ bool operator==(const SessionId& id) const;
+ // Convert to a string
+ std::string str() const;
+};
+
+std::ostream& operator<<(std::ostream&, const SessionId&);
+
+
+} // namespace qpid
+
+#endif /*!QPID_SESSIONID_H*/
diff --git a/RC9/qpid/cpp/src/qpid/SessionState.cpp b/RC9/qpid/cpp/src/qpid/SessionState.cpp
new file mode 100644
index 0000000000..ac75b5c5ff
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/SessionState.cpp
@@ -0,0 +1,278 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "SessionState.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/framing/AMQMethodBody.h"
+#include "qpid/framing/enum.h"
+#include "qpid/log/Statement.h"
+#include <boost/bind.hpp>
+#include <numeric>
+
+namespace qpid {
+using framing::AMQFrame;
+using framing::NotImplementedException;
+using framing::InvalidArgumentException;
+using framing::IllegalStateException;
+using framing::ResourceLimitExceededException;
+using framing::InternalErrorException;
+using framing::FramingErrorException;
+
+namespace {
+bool isControl(const AMQFrame& f) {
+ return f.getMethod() && f.getMethod()->type() == framing::SEGMENT_TYPE_CONTROL;
+}
+bool isCommand(const AMQFrame& f) {
+ return f.getMethod() && f.getMethod()->type() == framing::SEGMENT_TYPE_COMMAND;
+}
+} // namespace
+
+SessionPoint::SessionPoint(SequenceNumber c, uint64_t o) : command(c), offset(o) {}
+
+// TODO aconway 2008-05-22: Do complete frame sequence validity check here,
+// currently duplicated betwen broker and client session impl.
+//
+void SessionPoint::advance(const AMQFrame& f) {
+ if (isControl(f)) return; // Ignore controls.
+ if (f.isFirstSegment() && f.isFirstFrame()) {
+ if (offset != 0)
+ throw FramingErrorException(QPID_MSG("Unexpected command start frame."));
+ if (!isCommand(f))
+ throw FramingErrorException(
+ QPID_MSG("Command start frame has invalid type" << f.getBody()->type()));
+ if (f.isLastSegment() && f.isLastFrame())
+ ++command; // Single-frame command.
+ else
+ offset += f.encodedSize();
+ }
+ else { // continuation frame for partial command
+ if (offset == 0)
+ throw FramingErrorException(QPID_MSG("Unexpected command continuation frame."));
+ if (f.isLastSegment() && f.isLastFrame()) {
+ ++command;
+ offset = 0;
+ }
+ else {
+ // TODO aconway 2008-04-24: if we go to support for partial
+ // command replay, then it may be better to record the unframed
+ // data size in a command point rather than the framed size so
+ // that the relationship of fragment offsets to the replay
+ // list can be computed more easily.
+ //
+ offset += f.encodedSize();
+ }
+ }
+}
+
+bool SessionPoint::operator<(const SessionPoint& x) const {
+ return command < x.command || (command == x.command && offset < x.offset);
+}
+
+bool SessionPoint::operator==(const SessionPoint& x) const {
+ return command == x.command && offset == x.offset;
+}
+
+
+SessionState::SendState::SendState() : unflushedSize(), replaySize(), bytesSinceKnownCompleted() {}
+
+SessionState::ReceiveState::ReceiveState() : bytesSinceKnownCompleted() {}
+
+SessionPoint SessionState::senderGetCommandPoint() { return sender.sendPoint; }
+SequenceSet SessionState::senderGetIncomplete() const { return sender.incomplete; }
+SessionPoint SessionState::senderGetReplayPoint() const { return sender.replayPoint; }
+
+SessionState::ReplayRange SessionState::senderExpected(const SessionPoint& expect) {
+ if (expect < sender.replayPoint || sender.sendPoint < expect)
+ throw InvalidArgumentException(QPID_MSG(getId() << ": expected command-point out of range."));
+ QPID_LOG(debug, getId() << ": sender expected point moved to " << expect);
+ ReplayList::iterator i = sender.replayList.begin();
+ SessionPoint p = sender.replayPoint;
+ while (i != sender.replayList.end() && p.command < expect.command)
+ p.advance(*i++);
+ assert(p.command == expect.command);
+ return boost::make_iterator_range(i, sender.replayList.end());
+}
+
+void SessionState::senderRecord(const AMQFrame& f) {
+ if (isControl(f)) return; // Ignore control frames.
+ QPID_LOG_IF(debug, f.getMethod(), getId() << ": sent cmd " << sender.sendPoint.command << ": " << *f.getMethod());
+ stateful = true;
+ if (timeout) sender.replayList.push_back(f);
+ sender.unflushedSize += f.encodedSize();
+ sender.bytesSinceKnownCompleted += f.encodedSize();
+ sender.replaySize += f.encodedSize();
+ sender.incomplete += sender.sendPoint.command;
+ sender.sendPoint.advance(f);
+ if (config.replayHardLimit && config.replayHardLimit < sender.replaySize)
+ throw ResourceLimitExceededException("Replay buffer exceeeded hard limit");
+}
+
+static const uint32_t SPONTANEOUS_REQUEST_INTERVAL = 65536;
+
+bool SessionState::senderNeedFlush() const {
+ return (sender.sendPoint.command % SPONTANEOUS_REQUEST_INTERVAL == 0) ||
+ (config.replayFlushLimit && sender.unflushedSize >= config.replayFlushLimit);
+}
+
+void SessionState::senderRecordFlush() {
+ sender.flushPoint = sender.sendPoint;
+ sender.unflushedSize = 0;
+}
+
+bool SessionState::senderNeedKnownCompleted() const {
+ return config.replayFlushLimit && sender.bytesSinceKnownCompleted >= config.replayFlushLimit;
+}
+
+void SessionState::senderRecordKnownCompleted() {
+ sender.bytesSinceKnownCompleted = 0;
+}
+
+void SessionState::senderConfirmed(const SessionPoint& confirmed) {
+ if (confirmed > sender.sendPoint)
+ throw InvalidArgumentException(QPID_MSG(getId() << ": confirmed < " << confirmed << " but only sent < " << sender.sendPoint));
+ QPID_LOG(debug, getId() << ": sender confirmed point moved to " << confirmed);
+ ReplayList::iterator i = sender.replayList.begin();
+ while (i != sender.replayList.end() && sender.replayPoint.command < confirmed.command) {
+ sender.replayPoint.advance(*i);
+ assert(sender.replayPoint <= sender.sendPoint);
+ sender.replaySize -= i->encodedSize();
+ if (sender.replayPoint > sender.flushPoint)
+ sender.unflushedSize -= i->encodedSize();
+ ++i;
+ }
+ if (sender.replayPoint > sender.flushPoint)
+ sender.flushPoint = sender.replayPoint;
+ sender.replayList.erase(sender.replayList.begin(), i);
+ assert(sender.replayPoint.offset == 0);
+}
+
+void SessionState::senderCompleted(const SequenceSet& commands) {
+ if (commands.empty()) return;
+ QPID_LOG(debug, getId() << ": sender marked completed: " << commands);
+ sender.incomplete -= commands;
+ // Completion implies confirmation but we don't handle out-of-order
+ // confirmation, so confirm up to the end of the first contiguous range of commands.
+ senderConfirmed(SessionPoint(commands.rangesBegin()->end()));
+}
+
+void SessionState::receiverSetCommandPoint(const SessionPoint& point) {
+ if (hasState() && point > receiver.received)
+ throw InvalidArgumentException(QPID_MSG(getId() << ": Command-point out of range."));
+ QPID_LOG(debug, getId() << ": receiver command-point set to: " << point);
+ receiver.expected = point;
+ if (receiver.expected > receiver.received)
+ receiver.received = receiver.expected;
+}
+
+bool SessionState::receiverRecord(const AMQFrame& f) {
+ if (isControl(f)) return true; // Ignore control frames.
+ stateful = true;
+ receiver.expected.advance(f);
+ receiver.bytesSinceKnownCompleted += f.encodedSize();
+ bool firstTime = receiver.expected > receiver.received;
+ if (firstTime) {
+ receiver.received = receiver.expected;
+ receiver.incomplete += receiverGetCurrent();
+ }
+ QPID_LOG_IF(debug, f.getMethod(), getId() << ": recv cmd " << receiverGetCurrent() << ": " << *f.getMethod());
+ QPID_LOG_IF(debug, !firstTime, "Ignoring duplicate frame: " << receiverGetCurrent() << ": " << f);
+ return firstTime;
+}
+
+void SessionState::receiverCompleted(SequenceNumber command, bool cumulative) {
+ assert(receiver.incomplete.contains(command)); // Internal error to complete command twice.
+ SequenceNumber first =cumulative ? receiver.incomplete.front() : command;
+ SequenceNumber last = command;
+ receiver.unknownCompleted.add(first, last);
+ receiver.incomplete.remove(first, last);
+ QPID_LOG(debug, getId() << ": receiver marked completed: " << command
+ << " incomplete: " << receiver.incomplete
+ << " unknown-completed: " << receiver.unknownCompleted);
+}
+
+void SessionState::receiverKnownCompleted(const SequenceSet& commands) {
+ if (!commands.empty() && commands.back() > receiver.received.command)
+ throw InvalidArgumentException(QPID_MSG(getId() << ": Known-completed has invalid commands."));
+ receiver.bytesSinceKnownCompleted=0;
+ receiver.unknownCompleted -= commands;
+ QPID_LOG(debug, getId() << ": receiver known completed: " << commands << " unknown: " << receiver.unknownCompleted);
+}
+
+bool SessionState::receiverNeedKnownCompleted() const {
+ return (receiver.expected.command % SPONTANEOUS_REQUEST_INTERVAL == 0) ||
+ (config.replayFlushLimit && receiver.bytesSinceKnownCompleted >= config.replayFlushLimit);
+}
+
+const SessionPoint& SessionState::receiverGetExpected() const { return receiver.expected; }
+const SessionPoint& SessionState::receiverGetReceived() const { return receiver.received; }
+const SequenceSet& SessionState::receiverGetUnknownComplete() const { return receiver.unknownCompleted; }
+const SequenceSet& SessionState::receiverGetIncomplete() const { return receiver.incomplete; }
+
+SequenceNumber SessionState::receiverGetCurrent() const {
+ SequenceNumber current = receiver.expected.command;
+ if (receiver.expected.offset == 0)
+ --current;
+ return current;
+}
+
+SessionState::Configuration::Configuration(size_t flush, size_t hard) :
+ replayFlushLimit(flush), replayHardLimit(hard) {}
+
+SessionState::SessionState(const SessionId& i, const Configuration& c)
+ : id(i), timeout(), config(c), stateful()
+{
+ QPID_LOG(debug, "SessionState::SessionState " << id << ": " << this);
+}
+
+bool SessionState::hasState() const { return stateful; }
+
+SessionState::~SessionState() {}
+
+std::ostream& operator<<(std::ostream& o, const SessionPoint& p) {
+ return o << "(" << p.command.getValue() << "+" << p.offset << ")";
+}
+
+void SessionState::setState(
+ const SequenceNumber& replayStart,
+ const SequenceNumber& sendCommandPoint,
+ const SequenceSet& sentIncomplete,
+ const SequenceNumber& expected,
+ const SequenceNumber& received,
+ const SequenceSet& unknownCompleted,
+ const SequenceSet& receivedIncomplete
+)
+{
+ sender.replayPoint = replayStart;
+ sender.flushPoint = sendCommandPoint;
+ sender.sendPoint = sendCommandPoint;
+ sender.unflushedSize = 0;
+ sender.replaySize = 0; // Replay list will be updated separately.
+ sender.incomplete = sentIncomplete;
+ sender.bytesSinceKnownCompleted = 0;
+
+ receiver.expected = expected;
+ receiver.received = received;
+ receiver.unknownCompleted = unknownCompleted;
+ receiver.incomplete = receivedIncomplete;
+ receiver.bytesSinceKnownCompleted = 0;
+}
+
+} // namespace qpid
diff --git a/RC9/qpid/cpp/src/qpid/SessionState.h b/RC9/qpid/cpp/src/qpid/SessionState.h
new file mode 100644
index 0000000000..bf4ff6d326
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/SessionState.h
@@ -0,0 +1,219 @@
+#ifndef QPID_SESSIONSTATE_H
+#define QPID_SESSIONSTATE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/SessionId.h>
+#include <qpid/framing/SequenceNumber.h>
+#include <qpid/framing/SequenceSet.h>
+#include <qpid/framing/AMQFrame.h>
+#include <qpid/framing/FrameHandler.h>
+#include <boost/operators.hpp>
+#include <boost/range/iterator_range.hpp>
+#include <vector>
+#include <iosfwd>
+
+namespace qpid {
+using framing::SequenceNumber;
+using framing::SequenceSet;
+
+/** A point in the session. Points to command id + offset */
+struct SessionPoint : boost::totally_ordered1<SessionPoint> {
+ SessionPoint(SequenceNumber command = 0, uint64_t offset = 0);
+
+ SequenceNumber command;
+ uint64_t offset;
+
+ /** Advance past frame f */
+ void advance(const framing::AMQFrame& f);
+
+ bool operator<(const SessionPoint&) const;
+ bool operator==(const SessionPoint&) const;
+};
+
+std::ostream& operator<<(std::ostream&, const SessionPoint&);
+
+/**
+ * Support for session idempotence barrier and resume as defined in
+ * AMQP 0-10.
+ *
+ * We only issue/use contiguous confirmations, out-of-order confirmation
+ * is ignored. Out of order completion is fully supported.
+ *
+ * Raises NotImplemented if the command point is set greater than the
+ * max currently received command data, either explicitly via
+ * session.command-point or implicitly via session.gap.
+ *
+ * Partial replay is not supported, replay always begins on a command
+ * boundary, and we never confirm partial commands.
+ *
+ * The SessionPoint data structure does store offsets so this class
+ * could be extended to support partial replay without
+ * source-incompatbile API changes.
+ */
+class SessionState {
+ typedef std::vector<framing::AMQFrame> ReplayList;
+
+ public:
+
+ typedef boost::iterator_range<ReplayList::iterator> ReplayRange;
+
+ struct Configuration {
+ Configuration(size_t flush=1024*1024, size_t hard=0);
+ size_t replayFlushLimit; // Flush when the replay list >= N bytes. 0 disables.
+ size_t replayHardLimit; // Kill session if replay list > N bytes. 0 disables.
+ };
+
+ SessionState(const SessionId& =SessionId(), const Configuration& =Configuration());
+
+ virtual ~SessionState();
+
+ bool hasState() const;
+
+ const SessionId& getId() const { return id; }
+
+ uint32_t getTimeout() const { return timeout; }
+ void setTimeout(uint32_t seconds) { timeout = seconds; }
+
+ bool operator==(const SessionId& other) const { return id == other; }
+ bool operator==(const SessionState& other) const { return id == other.id; }
+
+ // ==== Functions for sender state.
+
+ /** Record frame f for replay. Should not be called during replay. */
+ virtual void senderRecord(const framing::AMQFrame& f);
+
+ /** @return true if we should send flush for confirmed and completed commands. */
+ virtual bool senderNeedFlush() const;
+
+ /** Called when flush for confirmed and completed commands is sent to peer. */
+ virtual void senderRecordFlush();
+
+ /** True if we should reply to the next incoming completed command */
+ virtual bool senderNeedKnownCompleted() const;
+
+ /** Called when knownCompleted is sent to peer. */
+ virtual void senderRecordKnownCompleted();
+
+ /** Called when the peer confirms up to comfirmed. */
+ virtual void senderConfirmed(const SessionPoint& confirmed);
+
+ /** Called when the peer indicates commands completed */
+ virtual void senderCompleted(const SequenceSet& commands);
+
+ /** Point from which the next new (not replayed) data will be sent. */
+ virtual SessionPoint senderGetCommandPoint();
+
+ /** Set of outstanding incomplete commands */
+ virtual SequenceSet senderGetIncomplete() const;
+
+ /** Point from which we can replay. */
+ virtual SessionPoint senderGetReplayPoint() const;
+
+ /** Peer expecting commands from this point.
+ *@return Range of frames to be replayed.
+ */
+ virtual ReplayRange senderExpected(const SessionPoint& expected);
+
+ // ==== Functions for receiver state
+
+ /** Set the command point. */
+ virtual void receiverSetCommandPoint(const SessionPoint& point);
+
+ /** Returns true if frame should be be processed, false if it is a duplicate. */
+ virtual bool receiverRecord(const framing::AMQFrame& f);
+
+ /** Command completed locally */
+ virtual void receiverCompleted(SequenceNumber command, bool cumulative=false);
+
+ /** Peer has indicated commands are known completed */
+ virtual void receiverKnownCompleted(const SequenceSet& commands);
+
+ /** True if the next completed control should set the timely-reply argument
+ * to request a knonw-completed response.
+ */
+ virtual bool receiverNeedKnownCompleted() const;
+
+ /** Get the incoming command point */
+ virtual const SessionPoint& receiverGetExpected() const;
+
+ /** Get the received high-water-mark, may be > getExpected() during replay */
+ virtual const SessionPoint& receiverGetReceived() const;
+
+ /** Completed received commands that the peer may not know about. */
+ virtual const SequenceSet& receiverGetUnknownComplete() const;
+
+ /** Incomplete received commands. */
+ virtual const SequenceSet& receiverGetIncomplete() const;
+
+ /** ID of the command currently being handled. */
+ virtual SequenceNumber receiverGetCurrent() const;
+
+ /** Set the state variables, used to create a session that will resume
+ * from some previously established point.
+ */
+ virtual void setState(
+ const SequenceNumber& replayStart,
+ const SequenceNumber& sendCommandPoint,
+ const SequenceSet& sentIncomplete,
+ const SequenceNumber& expected,
+ const SequenceNumber& received,
+ const SequenceSet& unknownCompleted,
+ const SequenceSet& receivedIncomplete
+ );
+
+ private:
+
+ struct SendState {
+ SendState();
+ // invariant: replayPoint <= flushPoint <= sendPoint
+ SessionPoint replayPoint; // Can replay from this point
+ SessionPoint flushPoint; // Point of last flush
+ SessionPoint sendPoint; // Send from this point
+ ReplayList replayList; // Starts from replayPoint.
+ size_t unflushedSize; // Un-flushed bytes in replay list.
+ size_t replaySize; // Total bytes in replay list.
+ SequenceSet incomplete; // Commands sent and not yet completed.
+ size_t bytesSinceKnownCompleted; // Bytes sent since we last issued a knownCompleted.
+ } sender;
+
+ struct ReceiveState {
+ ReceiveState();
+ SessionPoint expected; // Expected from here
+ SessionPoint received; // Received to here. Invariant: expected <= received.
+ SequenceSet unknownCompleted; // Received & completed, may not not known-complete by peer.
+ SequenceSet incomplete; // Incomplete received commands.
+ size_t bytesSinceKnownCompleted; // Bytes sent since we last issued a knownCompleted.
+ } receiver;
+
+ SessionId id;
+ uint32_t timeout;
+ Configuration config;
+ bool stateful;
+};
+
+inline bool operator==(const SessionId& id, const SessionState& s) { return s == id; }
+
+} // namespace qpid
+
+
+#endif /*!QPID_SESSIONSTATE_H*/
diff --git a/RC9/qpid/cpp/src/qpid/SharedObject.h b/RC9/qpid/cpp/src/qpid/SharedObject.h
new file mode 100644
index 0000000000..852a036ab9
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/SharedObject.h
@@ -0,0 +1,55 @@
+#ifndef _SharedObject_
+#define _SharedObject_
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <boost/shared_ptr.hpp>
+#include <boost/noncopyable.hpp>
+
+namespace qpid {
+ /**
+ * Template to enforce shared object conventions.
+ * Shared object classes should inherit : public qpid::SharedObject
+ * That ensures Foo:
+ * - has typedef boost::shared_ptr<T> shared_ptr
+ * - has virtual destructor
+ * - is boost::noncopyable (no default copy or assign)
+ * - has a protected default constructor.
+ *
+ * Shared objects should not have public constructors.
+ * Make constructors protected and provide public statc create()
+ * functions that return a shared_ptr.
+ */
+ template <class T>
+ class SharedObject : private boost::noncopyable
+ {
+ public:
+ typedef boost::shared_ptr<T> shared_ptr;
+
+ virtual ~SharedObject() {};
+
+ protected:
+ SharedObject() {}
+ };
+}
+
+#endif /*!_SharedObject_*/
diff --git a/RC9/qpid/cpp/src/qpid/StringUtils.cpp b/RC9/qpid/cpp/src/qpid/StringUtils.cpp
new file mode 100644
index 0000000000..17eb141e12
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/StringUtils.cpp
@@ -0,0 +1,50 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "StringUtils.h"
+
+namespace qpid {
+
+using std::string;
+using std::vector;
+
+void split(vector<string>& out, const string& in, const string& delims)
+{
+ string::size_type start = in.find_first_not_of(delims);
+ if (start == string::npos) return;
+
+ string::size_type end = in.find_first_of(delims, start);
+ while (end != string::npos) {
+ out.push_back(in.substr(start, end - start));
+ start = in.find_first_not_of(delims, end);
+ if (start == string::npos) return;
+ end = in.find_first_of(delims, start);
+ }
+ out.push_back(in.substr(start));
+}
+
+vector<string> split(const string& in, const string& delims)
+{
+ vector<string> out;
+ split(out, in, delims);
+ return out;
+}
+
+} // namespace qpid
diff --git a/RC9/qpid/cpp/src/qpid/StringUtils.h b/RC9/qpid/cpp/src/qpid/StringUtils.h
new file mode 100644
index 0000000000..3120e43334
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/StringUtils.h
@@ -0,0 +1,43 @@
+#ifndef QPID_STRINGUTILS_H
+#define QPID_STRINGUTILS_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <string>
+#include <vector>
+
+namespace qpid {
+
+/**
+ * Split 'in' into words using delimiters in 'delims' and put
+ * resulting strings into 'out' vector.
+ */
+void split(std::vector<std::string>& out, const std::string& in, const std::string& delims);
+/**
+ * Split 'in' into words using delimiters in 'delims' and return the
+ * resulting strings in a vector.
+ */
+std::vector<std::string> split(const std::string& in, const std::string& delims);
+
+} // namespace qpid
+
+#endif /*!QPID_STRINGUTILS_H*/
diff --git a/RC9/qpid/cpp/src/qpid/Url.cpp b/RC9/qpid/cpp/src/qpid/Url.cpp
new file mode 100644
index 0000000000..f831167dd8
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/Url.cpp
@@ -0,0 +1,212 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/Url.h"
+#include "qpid/Exception.h"
+#include "qpid/Msg.h"
+#include "qpid/sys/SystemInfo.h"
+#include "qpid/sys/StrError.h"
+
+#include <boost/lexical_cast.hpp>
+
+#include <algorithm>
+
+#include <string.h>
+
+using namespace std;
+using boost::lexical_cast;
+
+namespace qpid {
+
+Url::Invalid::Invalid(const string& s) : Exception(s) {}
+
+Url Url::getHostNameUrl(uint16_t port) {
+ TcpAddress address(std::string(), port);
+ if (!sys::SystemInfo::getLocalHostname(address))
+ throw Url::Invalid(QPID_MSG("Cannot get host name: " << qpid::sys::strError(errno)));
+ return Url(address);
+}
+
+Url Url::getIpAddressesUrl(uint16_t port) {
+ Url url;
+ sys::SystemInfo::getLocalIpAddresses(port, url);
+ return url;
+}
+
+string Url::str() const {
+ if (cache.empty() && !this->empty()) {
+ ostringstream os;
+ os << *this;
+ cache = os.str();
+ }
+ return cache;
+}
+
+ostream& operator<<(ostream& os, const Url& url) {
+ Url::const_iterator i = url.begin();
+ os << "amqp:";
+ if (i!=url.end()) {
+ os << *i++;
+ while (i != url.end())
+ os << "," << *i++;
+ }
+ return os;
+}
+
+
+/** Simple recursive-descent parser for url grammar in AMQP 0-10 spec:
+
+ amqp_url = "amqp:" prot_addr_list
+ prot_addr_list = [prot_addr ","]* prot_addr
+ prot_addr = tcp_prot_addr | tls_prot_addr
+
+ tcp_prot_addr = tcp_id tcp_addr
+ tcp_id = "tcp:" | ""
+ tcp_addr = [host [":" port] ]
+ host = <as per http://www.ietf.org/rfc/rfc3986.txt>
+ port = number]]>
+*/
+class UrlParser {
+ public:
+ UrlParser(Url& u, const char* s) : url(u), text(s), end(s+strlen(s)), i(s) {}
+ bool parse() { return literal("amqp:") && list(&UrlParser::protAddr, &UrlParser::comma) && i == end; }
+
+ private:
+ typedef bool (UrlParser::*Rule)();
+
+ bool comma() { return literal(","); }
+
+ // NOTE: tcpAddr must be last since it is allowed to omit it's tcp: tag.
+ bool protAddr() { return exampleAddr() || tcpAddr(); }
+
+ bool tcpAddr() {
+ TcpAddress addr;
+ literal("tcp:"); // Don't check result, allowed to be absent.
+ return addIf(host(addr.host) && (literal(":") ? port(addr.port) : true), addr);
+ }
+
+ // Placeholder address type till we have multiple address types. Address is a single char.
+ bool exampleAddr () {
+ if (literal("example:") && i < end) {
+ ExampleAddress ex(*i++);
+ url.push_back(ex);
+ return true;
+ }
+ return false;
+ }
+
+ // FIXME aconway 2008-11-20: this does not implement http://www.ietf.org/rfc/rfc3986.txt.
+ // Works for DNS names and ipv4 literals but won't handle ipv6.
+ bool host(string& h) {
+ const char* start=i;
+ while (unreserved() || pctEncoded())
+ ;
+ if (start == i) h = LOCALHOST; // Default
+ else h.assign(start, i);
+ return true;
+ }
+
+ bool unreserved() { return (::isalnum(*i) || ::strchr("-._~", *i)) && advance(); }
+
+ bool pctEncoded() { return literal("%") && hexDigit() && hexDigit(); }
+
+ bool hexDigit() { return i < end && ::strchr("01234567890abcdefABCDEF", *i) && advance(); }
+
+ bool port(uint16_t& p) { return decimalInt(p); }
+
+ template <class AddrType> bool addIf(bool ok, const AddrType& addr) { if (ok) url.push_back(addr); return ok; }
+
+ template <class IntType> bool decimalInt(IntType& n) {
+ const char* start = i;
+ while (decDigit())
+ ;
+ try {
+ n = lexical_cast<IntType>(string(start, i));
+ return true;
+ } catch(...) { return false; }
+ }
+
+ bool decDigit() { return i < end && ::isdigit(*i) && advance(); }
+
+ bool literal(const char* s) {
+ int n = ::strlen(s);
+ if (n <= end-i && equal(s, s+n, i)) return advance(n);
+ return false;
+ };
+
+ bool noop() { return true; }
+
+ /** List of item, separated by separator, with min & max bounds. */
+ bool list(Rule item, Rule separator, size_t min=0, size_t max=UNLIMITED) {
+ assert(max > 0);
+ assert(max >= min);
+ if (!(this->*item)()) return min == 0; // Empty list.
+ size_t n = 1;
+ while (n < max && i < end) {
+ if (!(this->*separator)()) break;
+ if (i == end || !(this->*item)()) return false; // Separator with no item.
+ ++n;
+ }
+ return n >= min;
+ }
+
+ /** List of items with no separator */
+ bool list(Rule item, size_t min=0, size_t max=UNLIMITED) { return list(item, &UrlParser::noop, min, max); }
+
+ bool advance(size_t n=1) {
+ if (i+n > end) return false;
+ i += n;
+ return true;
+ }
+
+ static const size_t UNLIMITED = size_t(~1);
+ static const std::string LOCALHOST;
+
+ Url& url;
+ const char* text;
+ const char* end;
+ const char* i;
+};
+
+const string UrlParser::LOCALHOST("127.0.0.1");
+
+void Url::parse(const char* url) {
+ parseNoThrow(url);
+ if (empty())
+ throw Url::Invalid(QPID_MSG("Invalid URL: " << url));
+}
+
+void Url::parseNoThrow(const char* url) {
+ cache.clear();
+ if (!UrlParser(*this, url).parse())
+ clear();
+}
+
+void Url::throwIfEmpty() const {
+ if (empty())
+ throw Url::Invalid("URL contains no addresses");
+}
+
+std::istream& operator>>(std::istream& is, Url& url) {
+ std::string s;
+ is >> s;
+ url.parse(s);
+ return is;
+}
+
+} // namespace qpid
diff --git a/RC9/qpid/cpp/src/qpid/Url.h b/RC9/qpid/cpp/src/qpid/Url.h
new file mode 100644
index 0000000000..07ca46e70c
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/Url.h
@@ -0,0 +1,92 @@
+#ifndef QPID_URL_H
+#define QPID_URL_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/Address.h"
+#include "qpid/Exception.h"
+#include <string>
+#include <vector>
+#include <new>
+#include <ostream>
+
+namespace qpid {
+
+std::ostream& operator<<(std::ostream& os, const TcpAddress& a);
+
+/** An AMQP URL contains a list of addresses */
+struct Url : public std::vector<Address> {
+
+ /** Url with the hostname as returned by gethostname(2) */
+ static Url getHostNameUrl(uint16_t port);
+
+ /** Url with local IP address(es), may be more than one address
+ * on a multi-homed host. */
+ static Url getIpAddressesUrl(uint16_t port);
+
+ struct Invalid : public Exception { Invalid(const std::string& s); };
+
+ /** Convert to string form. */
+ std::string str() const;
+
+ /** Empty URL. */
+ Url() {}
+
+ /** URL containing a single address */
+ explicit Url(const Address& addr) { push_back(addr); }
+
+ /** Parse url, throw Invalid if invalid. */
+ explicit Url(const std::string& url) { parse(url.c_str()); }
+
+ /** Parse url, throw Invalid if invalid. */
+ explicit Url(const char* url) { parse(url); }
+
+ Url& operator=(const Url& u) { this->std::vector<Address>::operator=(u); cache=u.cache; return *this; }
+ Url& operator=(const char* s) { parse(s); return *this; }
+ Url& operator=(const std::string& s) { parse(s); return *this; }
+
+ /** Throw Invalid if the URL does not contain any addresses. */
+ void throwIfEmpty() const;
+
+ /** Replace contents with parsed URL as defined in
+ * https://wiki.108.redhat.com/jira/browse/AMQP-95
+ *@exception Invalid if the url is invalid.
+ */
+ void parse(const char* url);
+ void parse(const std::string& url) { parse(url.c_str()); }
+
+ /** Replace contesnts with parsed URL as defined in
+ * https://wiki.108.redhat.com/jira/browse/AMQP-95
+ * url.empty() will be true if url is invalid.
+ */
+ void parseNoThrow(const char* url);
+
+ private:
+ mutable std::string cache; // cache string form for efficiency.
+};
+
+inline bool operator==(const Url& a, const Url& b) { return a.str()==b.str(); }
+inline bool operator!=(const Url& a, const Url& b) { return a.str()!=b.str(); }
+
+std::ostream& operator<<(std::ostream& os, const Url& url);
+std::istream& operator>>(std::istream& is, Url& url);
+
+} // namespace qpid
+
+#endif /*!QPID_URL_H*/
diff --git a/RC9/qpid/cpp/src/qpid/Version.h b/RC9/qpid/cpp/src/qpid/Version.h
new file mode 100755
index 0000000000..9bd561b7a9
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/Version.h
@@ -0,0 +1,44 @@
+#ifndef QPID_VERSION_H
+#define QPID_VERSION_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <string>
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+namespace qpid {
+#ifdef HAVE_CONFIG_H
+ const std::string product = PACKAGE_NAME;
+ const std::string version = PACKAGE_VERSION;
+# if HAVE_SASL
+ const std::string saslName = BROKER_SASL_NAME;
+# else
+ const std::string saslName = "qpidd-no-sasl";
+# endif
+#else
+ const std::string product = "qpidc";
+ const std::string version = "0.3";
+ const std::string saslName = "qpid-broker";
+#endif
+}
+
+#endif /*!QPID_VERSION_H*/
diff --git a/RC9/qpid/cpp/src/qpid/acl/Acl.cpp b/RC9/qpid/cpp/src/qpid/acl/Acl.cpp
new file mode 100644
index 0000000000..238ab9df6c
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/acl/Acl.cpp
@@ -0,0 +1,164 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/acl/Acl.h"
+#include "qpid/acl/AclData.h"
+
+#include "qpid/broker/Broker.h"
+#include "qpid/Plugin.h"
+#include "qpid/Options.h"
+#include "qpid/shared_ptr.h"
+#include "qpid/log/Logger.h"
+#include "qmf/org/apache/qpid/acl/Package.h"
+#include "qmf/org/apache/qpid/acl/EventAllow.h"
+#include "qmf/org/apache/qpid/acl/EventDeny.h"
+#include "qmf/org/apache/qpid/acl/EventFileLoaded.h"
+#include "qmf/org/apache/qpid/acl/EventFileLoadFailed.h"
+
+#include <map>
+
+#include <boost/utility/in_place_factory.hpp>
+
+using namespace std;
+using namespace qpid::acl;
+using qpid::management::ManagementAgent;
+using qpid::management::ManagementObject;
+using qpid::management::Manageable;
+using qpid::management::Args;
+namespace _qmf = qmf::org::apache::qpid::acl;
+
+Acl::Acl (AclValues& av, broker::Broker& b): aclValues(av), broker(&b), transferAcl(false)
+{
+
+ agent = ManagementAgent::Singleton::getInstance();
+
+ if (agent != 0){
+ _qmf::Package packageInit(agent);
+ mgmtObject = new _qmf::Acl (agent, this, broker);
+ agent->addObject (mgmtObject);
+ }
+
+ std::string errorString;
+ if (!readAclFile(errorString)){
+ throw Exception("Could not read ACL file " + errorString);
+ if (mgmtObject!=0) mgmtObject->set_enforcingAcl(0);
+ }
+ QPID_LOG(info, "ACL Plugin loaded");
+ if (mgmtObject!=0) mgmtObject->set_enforcingAcl(1);
+}
+
+ bool Acl::authorise(const std::string& id, const Action& action, const ObjectType& objType, const std::string& name, std::map<Property, std::string>* params)
+ {
+ boost::shared_ptr<AclData> dataLocal = data; //rcu copy
+
+ // add real ACL check here...
+ AclResult aclreslt = dataLocal->lookup(id,action,objType,name,params);
+
+
+ return result(aclreslt, id, action, objType, name);
+ }
+
+ bool Acl::authorise(const std::string& id, const Action& action, const ObjectType& objType, const std::string& ExchangeName, const std::string& RoutingKey)
+ {
+ boost::shared_ptr<AclData> dataLocal = data; //rcu copy
+
+ // only use dataLocal here...
+ AclResult aclreslt = dataLocal->lookup(id,action,objType,ExchangeName,RoutingKey);
+
+ return result(aclreslt, id, action, objType, ExchangeName);
+ }
+
+
+ bool Acl::result(const AclResult& aclreslt, const std::string& id, const Action& action, const ObjectType& objType, const std::string& name)
+ {
+ switch (aclreslt)
+ {
+ case ALLOWLOG:
+ QPID_LOG(info, "ACL Allow id:" << id <<" action:" << AclHelper::getActionStr(action) <<
+ " ObjectType:" << AclHelper::getObjectTypeStr(objType) << " Name:" << name );
+ agent->raiseEvent(_qmf::EventAllow(id, AclHelper::getActionStr(action),
+ AclHelper::getObjectTypeStr(objType),
+ name, framing::FieldTable()));
+ case ALLOW:
+ return true;
+ case DENY:
+ if (mgmtObject!=0) mgmtObject->inc_aclDenyCount();
+ return false;
+ case DENYLOG:
+ if (mgmtObject!=0) mgmtObject->inc_aclDenyCount();
+ default:
+ QPID_LOG(info, "ACL Deny id:" << id << " action:" << AclHelper::getActionStr(action) << " ObjectType:" << AclHelper::getObjectTypeStr(objType) << " Name:" << name);
+ agent->raiseEvent(_qmf::EventDeny(id, AclHelper::getActionStr(action),
+ AclHelper::getObjectTypeStr(objType),
+ name, framing::FieldTable()));
+ return false;
+ }
+ return false;
+ }
+
+ bool Acl::readAclFile(std::string& errorText)
+ {
+ // only set transferAcl = true if a rule implies the use of ACL on transfer, else keep false for permormance reasons.
+ return readAclFile(aclValues.aclFile, errorText);
+ }
+
+ bool Acl::readAclFile(std::string& aclFile, std::string& errorText) {
+ boost::shared_ptr<AclData> d(new AclData);
+ AclReader ar;
+ if (ar.read(aclFile, d)){
+ agent->raiseEvent(_qmf::EventFileLoadFailed("", ar.getError()));
+ errorText = ar.getError();
+ QPID_LOG(error,ar.getError());
+ return false;
+ }
+
+ data = d;
+ transferAcl = data->transferAcl; // any transfer ACL
+ if (mgmtObject!=0){
+ mgmtObject->set_transferAcl(transferAcl?1:0);
+ mgmtObject->set_policyFile(aclFile);
+ sys::AbsTime now = sys::AbsTime::now();
+ int64_t ns = sys::Duration(now);
+ mgmtObject->set_lastAclLoad(ns);
+ agent->raiseEvent(_qmf::EventFileLoaded(""));
+ }
+ return true;
+ }
+
+ Acl::~Acl(){}
+
+ ManagementObject* Acl::GetManagementObject(void) const
+ {
+ return (ManagementObject*) mgmtObject;
+ }
+
+ Manageable::status_t Acl::ManagementMethod (uint32_t methodId, Args& /*args*/, string& text)
+ {
+ Manageable::status_t status = Manageable::STATUS_UNKNOWN_METHOD;
+ QPID_LOG (debug, "Queue::ManagementMethod [id=" << methodId << "]");
+
+ switch (methodId)
+ {
+ case _qmf::Acl::METHOD_RELOADACLFILE :
+ readAclFile(text);
+ status = Manageable::STATUS_USER;
+ break;
+ }
+
+ return status;
+}
diff --git a/RC9/qpid/cpp/src/qpid/acl/Acl.h b/RC9/qpid/cpp/src/qpid/acl/Acl.h
new file mode 100644
index 0000000000..2a522bc56d
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/acl/Acl.h
@@ -0,0 +1,85 @@
+#ifndef QPID_ACL_ACL_H
+#define QPID_ACL_ACL_H
+
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+
+#include "qpid/acl/AclReader.h"
+#include "qpid/shared_ptr.h"
+#include "qpid/RefCounted.h"
+#include "qpid/broker/AclModule.h"
+#include "qpid/management/Manageable.h"
+#include "qpid/agent/ManagementAgent.h"
+#include "qmf/org/apache/qpid/acl/Acl.h"
+
+#include <map>
+#include <string>
+
+
+namespace qpid {
+namespace broker {
+class Broker;
+}
+
+namespace acl {
+
+struct AclValues {
+ std::string aclFile;
+};
+
+
+class Acl : public broker::AclModule, public RefCounted, public management::Manageable
+{
+
+private:
+ acl::AclValues aclValues;
+ broker::Broker* broker;
+ bool transferAcl;
+ boost::shared_ptr<AclData> data;
+ qmf::org::apache::qpid::acl::Acl* mgmtObject; // mgnt owns lifecycle
+ qpid::management::ManagementAgent* agent;
+
+public:
+ Acl (AclValues& av, broker::Broker& b);
+
+ void initialize();
+
+ inline virtual bool doTransferAcl() {return transferAcl;};
+
+ // create specilied authorise methods for cases that need faster matching as needed.
+ virtual bool authorise(const std::string& id, const Action& action, const ObjectType& objType, const std::string& name, std::map<Property, std::string>* params=0);
+ virtual bool authorise(const std::string& id, const Action& action, const ObjectType& objType, const std::string& ExchangeName,const std::string& RoutingKey);
+
+ virtual ~Acl();
+private:
+ bool result(const AclResult& aclreslt, const std::string& id, const Action& action, const ObjectType& objType, const std::string& name);
+ bool readAclFile(std::string& errorText);
+ bool readAclFile(std::string& aclFile, std::string& errorText);
+ virtual qpid::management::ManagementObject* GetManagementObject(void) const;
+ virtual management::Manageable::status_t ManagementMethod (uint32_t methodId, management::Args& args, std::string& text);
+
+};
+
+
+
+}} // namespace qpid::acl
+
+#endif // QPID_ACL_ACL_H
diff --git a/RC9/qpid/cpp/src/qpid/acl/AclData.cpp b/RC9/qpid/cpp/src/qpid/acl/AclData.cpp
new file mode 100644
index 0000000000..d2a55c0027
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/acl/AclData.cpp
@@ -0,0 +1,162 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/acl/AclData.h"
+#include "qpid/log/Statement.h"
+
+
+namespace qpid {
+namespace acl {
+
+AclData::AclData():decisionMode(qpid::acl::DENY),transferAcl(false)
+{
+ for (unsigned int cnt=0; cnt< qpid::acl::ACTIONSIZE; cnt++){
+ actionList[cnt]=0;
+ }
+
+}
+
+void AclData::clear ()
+{
+ for (unsigned int cnt=0; cnt< qpid::acl::ACTIONSIZE; cnt++){
+ if (actionList[cnt]){
+ for (unsigned int cnt1=0; cnt1< qpid::acl::OBJECTSIZE; cnt1++)
+ delete actionList[cnt][cnt1];
+ }
+ delete[] actionList[cnt];
+ }
+
+}
+
+bool AclData::matchProp(const std::string & src, const std::string& src1)
+{
+ // allow wildcard on the end of strings...
+ if (src.data()[src.size()-1]=='*') {
+ return (src.compare(0, src.size()-1, src1, 0,src.size()-1 ) == 0);
+ } else {
+ return (src.compare(src1)==0) ;
+ }
+}
+
+AclResult AclData::lookup(const std::string& id, const Action& action, const ObjectType& objType, const std::string& name, std::map<Property, std::string>* params)
+{
+ AclResult aclresult = decisionMode;
+
+ if (actionList[action] && actionList[action][objType]){
+ AclData::actObjItr itrRule = actionList[action][objType]->find(id);
+ if (itrRule == actionList[action][objType]->end())
+ itrRule = actionList[action][objType]->find("*");
+ if (itrRule != actionList[action][objType]->end() ) {
+
+ //loop the vector
+ for (ruleSetItr i=itrRule->second.begin(); i<itrRule->second.end(); i++) {
+
+ // loop the names looking for match
+ bool match =true;
+ for (propertyMapItr pMItr = i->props.begin(); (pMItr != i->props.end()) && match; pMItr++)
+ {
+ //match name is exists first
+ if (pMItr->first == acl::PROP_NAME){
+ if (!matchProp(pMItr->second, name)){
+ match= false;
+ }
+ }else if (params){ //match pMItr against params
+ propertyMapItr paramItr = params->find (pMItr->first);
+ if (paramItr == params->end()){
+ match = false;
+ }else if (!matchProp(paramItr->second, pMItr->second)){
+ match = false;
+ }
+ }
+ }
+ if (match) return getACLResult(i->logOnly, i->log);
+ }
+ }
+ }
+ return aclresult;
+}
+
+AclResult AclData::lookup(const std::string& id, const Action& action, const ObjectType& objType, const std::string& /*Exchange*/ name, const std::string& RoutingKey)
+{
+ AclResult aclresult = decisionMode;
+
+ if (actionList[action] && actionList[action][objType]){
+ AclData::actObjItr itrRule = actionList[action][objType]->find(id);
+ if (itrRule == actionList[action][objType]->end())
+ itrRule = actionList[action][objType]->find("*");
+ if (itrRule != actionList[action][objType]->end() ) {
+
+ //loop the vector
+ for (ruleSetItr i=itrRule->second.begin(); i<itrRule->second.end(); i++) {
+
+ // loop the names looking for match
+ bool match =true;
+ for (propertyMapItr pMItr = i->props.begin(); (pMItr != i->props.end()) && match; pMItr++)
+ {
+ //match name is exists first
+ if (pMItr->first == acl::PROP_NAME){
+ if (!matchProp(pMItr->second, name)){
+ match= false;
+ }
+ }else if (pMItr->first == acl::PROP_ROUTINGKEY){
+ if (!matchProp(pMItr->second, RoutingKey)){
+ match= false;
+ }
+ }
+ }
+ if (match) return getACLResult(i->logOnly, i->log);
+ }
+ }
+ }
+ return aclresult;
+
+}
+
+
+AclResult AclData::getACLResult(bool logOnly, bool log)
+{
+ switch (decisionMode)
+ {
+ case qpid::acl::ALLOWLOG:
+ case qpid::acl::ALLOW:
+ if (logOnly) return qpid::acl::ALLOWLOG;
+ if (log)
+ return qpid::acl::DENYLOG;
+ else
+ return qpid::acl::DENY;
+
+
+ case qpid::acl::DENYLOG:
+ case qpid::acl::DENY:
+ if (logOnly) return qpid::acl::DENYLOG;
+ if (log)
+ return qpid::acl::ALLOWLOG;
+ else
+ return qpid::acl::ALLOW;
+ }
+
+ QPID_LOG(error, "ACL Decision Failed, setting DENY");
+ return qpid::acl::DENY;
+}
+
+AclData::~AclData()
+{
+ clear();
+}
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/acl/AclData.h b/RC9/qpid/cpp/src/qpid/acl/AclData.h
new file mode 100644
index 0000000000..249c3523eb
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/acl/AclData.h
@@ -0,0 +1,73 @@
+#ifndef QPID_ACL_ACLDATA_H
+#define QPID_ACL_ACLDATA_H
+
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/broker/AclModule.h"
+#include <vector>
+
+
+namespace qpid {
+namespace acl {
+
+class AclData {
+
+
+public:
+
+ typedef std::map<qpid::acl::Property, std::string> propertyMap;
+ typedef propertyMap::const_iterator propertyMapItr;
+ struct rule {
+
+ bool log;
+ bool logOnly; // this is a rule is to log only
+
+ // key value map
+ //??
+ propertyMap props;
+
+
+ rule (propertyMap& p):log(false),logOnly(false),props(p) {};
+ };
+ typedef std::vector<rule> ruleSet;
+ typedef ruleSet::const_iterator ruleSetItr;
+ typedef std::map<std::string, ruleSet > actionObject; // user
+ typedef actionObject::iterator actObjItr;
+ typedef actionObject* aclAction;
+
+ // Action*[] -> Object*[] -> map<user -> set<Rule> >
+ aclAction* actionList[qpid::acl::ACTIONSIZE];
+ qpid::acl::AclResult decisionMode; // determines if the rule set is an deny or accept basis.
+ bool transferAcl;
+
+ AclResult lookup(const std::string& id, const Action& action, const ObjectType& objType, const std::string& name, std::map<Property, std::string>* params=0);
+ AclResult lookup(const std::string& id, const Action& action, const ObjectType& objType, const std::string& ExchangeName, const std::string& RoutingKey);
+ AclResult getACLResult(bool logOnly, bool log);
+
+ bool matchProp(const std::string & src, const std::string& src1);
+ void clear ();
+
+ AclData();
+ virtual ~AclData();
+};
+
+}} // namespace qpid::acl
+
+#endif // QPID_ACL_ACLDATA_H
diff --git a/RC9/qpid/cpp/src/qpid/acl/AclPlugin.cpp b/RC9/qpid/cpp/src/qpid/acl/AclPlugin.cpp
new file mode 100644
index 0000000000..7310139041
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/acl/AclPlugin.cpp
@@ -0,0 +1,101 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <sstream>
+#include "qpid/acl/Acl.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/Plugin.h"
+#include "qpid/Options.h"
+#include "qpid/shared_ptr.h"
+#include "qpid/log/Statement.h"
+
+#include <boost/utility/in_place_factory.hpp>
+
+namespace qpid {
+namespace acl {
+
+using namespace std;
+
+/** Note separating options from values to work around boost version differences.
+ * Old boost takes a reference to options objects, but new boost makes a copy.
+ * New boost allows a shared_ptr but that's not compatible with old boost.
+ */
+struct AclOptions : public Options {
+ AclValues& values;
+
+ AclOptions(AclValues& v) : Options("ACL Options"), values(v) {
+ addOptions()
+ ("acl-file", optValue(values.aclFile, "FILE"), "The policy file to load from, loaded from data dir");
+ }
+};
+
+struct AclPlugin : public Plugin {
+
+ AclValues values;
+ AclOptions options;
+ boost::intrusive_ptr<Acl> acl;
+
+ AclPlugin() : options(values) {}
+
+ Options* getOptions() { return &options; }
+
+ void init(broker::Broker& b) {
+ if (values.aclFile.empty()){
+ QPID_LOG(info, "Policy file not specified. ACL Disabled, no ACL checking being done!");
+ return;
+ }
+
+ if (acl) throw Exception("ACL plugin cannot be initialized twice in one process.");
+
+ if (values.aclFile.at(0) == '/')
+ {
+ values.aclFile = values.aclFile;
+ }
+ else
+ {
+ std::ostringstream oss;
+ oss << b.getDataDir().getPath() << "/" << values.aclFile;
+ values.aclFile = oss.str();
+ }
+
+ acl = new Acl(values, b);
+ b.setAcl(acl.get());
+ b.addFinalizer(boost::bind(&AclPlugin::shutdown, this));
+ }
+
+ template <class T> bool init(Plugin::Target& target) {
+ T* t = dynamic_cast<T*>(&target);
+ if (t) init(*t);
+ return t;
+ }
+
+ void earlyInitialize(Plugin::Target&) {}
+
+ void initialize(Plugin::Target& target) {
+ init<broker::Broker>(target);
+ }
+
+ void shutdown() { acl = 0; }
+};
+
+static AclPlugin instance; // Static initialization.
+
+// For test purposes.
+boost::intrusive_ptr<Acl> getGlobalAcl() { return instance.acl; }
+
+}} // namespace qpid::acl
diff --git a/RC9/qpid/cpp/src/qpid/acl/AclReader.cpp b/RC9/qpid/cpp/src/qpid/acl/AclReader.cpp
new file mode 100644
index 0000000000..c407339390
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/acl/AclReader.cpp
@@ -0,0 +1,511 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/acl/AclReader.h"
+
+#include <cctype>
+#include <cstring>
+#include <fstream>
+#include <sstream>
+#include "qpid/log/Statement.h"
+#include "qpid/Exception.h"
+
+#include <iomanip> // degug
+#include <iostream> // debug
+
+#define ACL_FORMAT_ERR_LOG_PREFIX "ACL format error: " << fileName << ":" << lineNumber << ": "
+
+namespace qpid {
+namespace acl {
+
+AclReader::aclRule::aclRule(const AclResult r, const std::string n, const groupMap& groups) : res(r), actionAll(true), objStatus(NONE) {
+ processName(n, groups);
+}
+AclReader::aclRule::aclRule(const AclResult r, const std::string n, const groupMap& groups, const Action a) : res(r), actionAll(false), action(a), objStatus(NONE) {
+ processName(n, groups);
+}
+
+void AclReader::aclRule::setObjectType(const ObjectType o) {
+ objStatus = VALUE;
+ object = o;
+}
+
+void AclReader::aclRule::setObjectTypeAll() {
+ objStatus = ALL;
+}
+
+bool AclReader::aclRule::addProperty(const Property p, const std::string v) {
+ return props.insert(propNvPair(p, v)).second;
+}
+
+bool AclReader::aclRule::validate(const AclHelper::objectMapPtr& /*validationMap*/) {
+ // TODO - invalid rules won't ever be called in real life...
+ return true;
+}
+
+// Debug aid
+std::string AclReader::aclRule::toString() {
+ std::ostringstream oss;
+ oss << AclHelper::getAclResultStr(res) << " [";
+ for (nsCitr itr = names.begin(); itr != names.end(); itr++) {
+ if (itr != names.begin()) oss << ", ";
+ oss << *itr;
+ }
+ oss << "]";
+ if (actionAll) {
+ oss << " *";
+ } else {
+ oss << " " << AclHelper::getActionStr(action);
+ }
+ if (objStatus == ALL) {
+ oss << " *";
+ } else if (objStatus == VALUE) {
+ oss << " " << AclHelper::getObjectTypeStr(object);
+ }
+ for (pmCitr i=props.begin(); i!=props.end(); i++) {
+ oss << " " << AclHelper::getPropertyStr(i->first) << "=" << i->second;
+ }
+ return oss.str();
+}
+
+void AclReader::loadDecisionData( boost::shared_ptr<AclData> d )
+{
+ d->clear();
+ QPID_LOG(debug, "ACL Load Rules");
+ int cnt = rules.size();
+ bool foundmode = false;
+ for (rlCitr i=rules.end()-1; cnt; i--,cnt--) {
+ QPID_LOG(debug, "ACL Processing " << std::setfill(' ') << std::setw(2) << cnt << " " << (*i)->toString());
+
+ if (!foundmode && (*i)->actionAll && (*i)->names.size()==1 && (*((*i)->names.begin())).compare("*")==0 ){
+ d->decisionMode = (*i)->res;
+ QPID_LOG(debug, "ACL FoundMode " << AclHelper::getAclResultStr(d->decisionMode));
+ foundmode=true;
+ }else{
+ AclData::rule rule((*i)->props);
+ bool addrule= true;
+
+ switch ((*i)->res)
+ {
+ case qpid::acl::ALLOWLOG:
+ rule.log = true;
+ if (d->decisionMode == qpid::acl::ALLOW || d->decisionMode == qpid::acl::ALLOWLOG)
+ rule.logOnly = true;
+ break;
+ case qpid::acl::ALLOW:
+ if (d->decisionMode == qpid::acl::ALLOW || d->decisionMode == qpid::acl::ALLOWLOG)
+ addrule = false;
+ break;
+ case qpid::acl::DENYLOG:
+ rule.log = true;
+ if (d->decisionMode == qpid::acl::DENY || d->decisionMode == qpid::acl::DENYLOG)
+ rule.logOnly = true;
+ break;
+ case qpid::acl::DENY:
+ if (d->decisionMode == qpid::acl::DENY || d->decisionMode == qpid::acl::DENYLOG)
+ addrule = false;
+ break;
+ default:
+ throw Exception("Invalid ACL Result loading rules.");
+ }
+
+
+ // Action -> Object -> map<user -> set<Rule> >
+ if (addrule){
+ for (int acnt= ((*i)->actionAll?0:(*i)->action);
+ acnt< acl::ACTIONSIZE; (*i)->actionAll?acnt++:acnt=acl::ACTIONSIZE ) {
+
+ if (acnt == acl::ACT_PUBLISH) d->transferAcl = true; // we have transfer ACL
+
+ QPID_LOG(debug, "ACL Adding action:" << AclHelper::getActionStr((Action)acnt) );
+
+ //find the Action, create if not exist
+ if (d->actionList[acnt]==NULL) {
+ d->actionList[acnt] = new AclData::aclAction[qpid::acl::OBJECTSIZE];
+ for (int j=0;j<qpid::acl::OBJECTSIZE; j++)
+ d->actionList[acnt][j] = NULL;
+ }
+
+ // optimize this loop to limit to valid options only!!
+ for (int ocnt= ((*i)->objStatus!=aclRule::VALUE ?0:(*i)->object);
+ ocnt< acl::OBJECTSIZE;
+ (*i)->objStatus!=aclRule::VALUE?ocnt++:ocnt=acl::OBJECTSIZE ) {
+
+ QPID_LOG(debug, "ACL Adding object:" << AclHelper::getObjectTypeStr((ObjectType)ocnt) );
+
+ //find the Object, create if not exist
+ if (d->actionList[acnt][ocnt] == NULL)
+ d->actionList[acnt][ocnt] = new AclData::actionObject;
+
+ // add users and Rule to object set
+ bool allNames=false;
+ // check to see if names.begin is '*'
+ if ( (*(*i)->names.begin()).compare("*")==0 ) allNames = true;
+
+ for (nsCitr itr = (allNames?names.begin():(*i)->names.begin());
+ itr != (allNames?names.end():(*i)->names.end()); itr++) {
+ AclData::actObjItr itrRule = d->actionList[acnt][ocnt]->find(*itr);
+ if (itrRule == d->actionList[acnt][ocnt]->end()) {
+ QPID_LOG(debug, "ACL Adding rule & user:" << *itr);
+ AclData::ruleSet rSet;
+ rSet.push_back(rule);
+ d->actionList[acnt][ocnt]->insert(make_pair( std::string(*itr) , rSet) );
+ }else{
+
+ // TODO add code to check for dead rules
+ // allow peter create queue name=tmp <-- dead rule!!
+ // allow peter create queue
+
+ itrRule->second.push_back(rule);
+ QPID_LOG(debug, "ACL Adding rule to user:" << *itr);
+ }
+ }
+
+ }
+
+ }
+ }else{
+ QPID_LOG(debug, "ACL Skipping based on Mode:" << AclHelper::getAclResultStr(d->decisionMode) );
+ }
+ }
+
+ }
+
+
+}
+
+
+
+
+void AclReader::aclRule::processName(const std::string& name, const groupMap& groups) {
+ if (name.compare("all") == 0) {
+ names.insert("*");
+ } else {
+ gmCitr itr = groups.find(name);
+ if (itr == groups.end()) {
+ names.insert(name);
+ } else {
+ names.insert(itr->second->begin(), itr->second->end());
+ }
+ }
+}
+
+AclReader::AclReader() : lineNumber(0), contFlag(false), validationMap(new AclHelper::objectMap) {
+ AclHelper::loadValidationMap(validationMap);
+ names.insert("*");
+}
+
+AclReader::~AclReader() {}
+
+std::string AclReader::getError() {
+ return errorStream.str();
+}
+
+int AclReader::read(const std::string& fn, boost::shared_ptr<AclData> d) {
+ fileName = fn;
+ lineNumber = 0;
+ char buff[1024];
+ std::ifstream ifs(fn.c_str(), std::ios_base::in);
+ if (!ifs.good()) {
+ errorStream << "Unable to open ACL file \"" << fn << "\": eof=" << (ifs.eof()?"T":"F") << "; fail=" << (ifs.fail()?"T":"F") << "; bad=" << (ifs.bad()?"T":"F");
+ return -1;
+ }
+ try {
+ bool err = false;
+ while (ifs.good()) {
+ ifs.getline(buff, 1024);
+ lineNumber++;
+ if (std::strlen(buff) > 0 && buff[0] != '#') // Ignore blank lines and comments
+ err |= !processLine(buff);
+ }
+ if (!ifs.eof())
+ {
+ errorStream << "Unable to read ACL file \"" << fn << "\": eof=" << (ifs.eof()?"T":"F") << "; fail=" << (ifs.fail()?"T":"F") << "; bad=" << (ifs.bad()?"T":"F");
+ ifs.close();
+ return -2;
+ }
+ ifs.close();
+ if (err) return -3;
+ QPID_LOG(notice, "Read ACL file \"" << fn << "\"");
+ } catch (const std::exception& e) {
+ errorStream << "Unable to read ACL file \"" << fn << "\": " << e.what();
+ ifs.close();
+ return -4;
+ } catch (...) {
+ errorStream << "Unable to read ACL file \"" << fn << "\": Unknown exception";
+ ifs.close();
+ return -5;
+ }
+ printNames();
+ printRules();
+ loadDecisionData(d);
+
+ return 0;
+}
+
+bool AclReader::processLine(char* line) {
+ bool ret = false;
+ std::vector<std::string> toks;
+
+ // Check for continuation
+ char* contCharPtr = std::strrchr(line, '\\');
+ bool cont = contCharPtr != 0;
+ if (cont) *contCharPtr = 0;
+
+ int numToks = tokenize(line, toks);
+ if (numToks && (toks[0].compare("group") == 0 || contFlag)) {
+ ret = processGroupLine(toks, cont);
+ } else if (numToks && toks[0].compare("acl") == 0) {
+ ret = processAclLine(toks);
+ } else {
+ // Check for whitespace only line, ignore these
+ bool ws = true;
+ for (unsigned i=0; i<std::strlen(line) && ws; i++) {
+ if (!std::isspace(line[i])) ws = false;
+ }
+ if (ws) {
+ ret = true;
+ } else {
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Non-continuation line must start with \"group\" or \"acl\".";
+ ret = false;
+ }
+ }
+ contFlag = cont;
+ return ret;
+}
+
+int AclReader::tokenize(char* line, std::vector<std::string>& toks) {
+ const char* tokChars = " \t\n\f\v\r";
+ int cnt = 0;
+ char* cp = std::strtok(line, tokChars);
+ while (cp != 0) {
+ toks.push_back(std::string(cp));
+ cnt++;
+ cp = std::strtok(0, tokChars);
+ }
+ return cnt;
+}
+
+// Return true if the line is successfully processed without errors
+// If cont is true, then groupName must be set to the continuation group name
+bool AclReader::processGroupLine(tokList& toks, const bool cont) {
+ const unsigned toksSize = toks.size();
+ if (contFlag) {
+ gmCitr citr = groups.find(groupName);
+ for (unsigned i = 0; i < toksSize; i++) {
+ if (!checkName(toks[i])) {
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Name \"" << toks[i] << "\" contains illegal characters.";
+ return false;
+ }
+ addName(toks[i], citr->second);
+ }
+ } else {
+ if (toksSize < (cont ? 2 : 3)) {
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Insufficient tokens for group definition.";
+ return false;
+ }
+ if (!checkName(toks[1])) {
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Group name \"" << toks[1] << "\" contains illegal characters.";
+ return false;
+ }
+ gmCitr citr = addGroup(toks[1]);
+ if (citr == groups.end()) return false;
+ for (unsigned i = 2; i < toksSize; i++) {
+ if (!checkName(toks[i])) {
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Name \"" << toks[i] << "\" contains illegal characters.";
+ return false;
+ }
+ addName(toks[i], citr->second);
+ }
+ }
+ return true;
+}
+
+// Return true if sucessfully added group
+AclReader::gmCitr AclReader::addGroup(const std::string& newGroupName) {
+ gmCitr citr = groups.find(newGroupName);
+ if (citr != groups.end()) {
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Duplicate group name \"" << newGroupName << "\".";
+ return groups.end();
+ }
+ groupPair p(newGroupName, nameSetPtr(new nameSet));
+ gmRes res = groups.insert(p);
+ assert(res.second);
+ groupName = newGroupName;
+ return res.first;
+}
+
+void AclReader::addName(const std::string& name, nameSetPtr groupNameSet) {
+ gmCitr citr = groups.find(name);
+ if (citr != groups.end() && citr->first != name){
+ // This is a previously defined group: add all the names in that group to this group
+ groupNameSet->insert(citr->second->begin(), citr->second->end());
+ } else {
+ // Not a known group name
+ groupNameSet->insert(name);
+ addName(name);
+ }
+}
+
+void AclReader::addName(const std::string& name) {
+ names.insert(name);
+}
+
+// Debug aid
+void AclReader::printNames() const {
+ QPID_LOG(debug, "Group list: " << groups.size() << " groups found:" );
+ std::string tmp;
+ for (gmCitr i=groups.begin(); i!= groups.end(); i++) {
+ tmp += " \"";
+ tmp += i->first;
+ tmp += "\":";
+ for (nsCitr j=i->second->begin(); j!=i->second->end(); j++) {
+ tmp += " ";
+ tmp += *j;
+ }
+ QPID_LOG(debug, tmp);
+ tmp.clear();
+ }
+ QPID_LOG(debug, "Name list: " << names.size() << " names found:" );
+ tmp.clear();
+ for (nsCitr k=names.begin(); k!=names.end(); k++) {
+ tmp += " ";
+ tmp += *k;
+ }
+ QPID_LOG(debug, tmp);
+}
+
+bool AclReader::processAclLine(tokList& toks) {
+ const unsigned toksSize = toks.size();
+ if (toksSize < 4) {
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Insufficient tokens for acl definition.";
+ return false;
+ }
+
+ AclResult res;
+ try {
+ res = AclHelper::getAclResult(toks[1]);
+ } catch (...) {
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Unknown ACL permission \"" << toks[1] << "\".";
+ return false;
+ }
+
+ bool actionAllFlag = toks[3].compare("all") == 0;
+ bool userAllFlag = toks[2].compare("all") == 0;
+ Action action;
+ if (actionAllFlag) {
+
+ if (userAllFlag && toksSize > 4) {
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Tokens found after action \"all\".";
+ return false;
+ }
+ action = ACT_CONSUME; // dummy; compiler must initialize action for this code path
+ } else {
+ try {
+ action = AclHelper::getAction(toks[3]);
+ } catch (...) {
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Unknown action \"" << toks[3] << "\".";
+ return false;
+ }
+ }
+
+ // Create rule obj; then add object (if any) and properties (if any)
+ aclRulePtr rule;
+ if (actionAllFlag) {
+ rule.reset(new aclRule(res, toks[2], groups));
+ } else {
+ rule.reset(new aclRule(res, toks[2], groups, action));
+ }
+
+ if (toksSize >= 5) { // object name-value pair
+ if (toks[4].compare("all") == 0) {
+ rule->setObjectTypeAll();
+ } else {
+ try {
+ rule->setObjectType(AclHelper::getObjectType(toks[4]));
+ } catch (...) {
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Unknown object \"" << toks[4] << "\".";
+ return false;
+ }
+ }
+ }
+
+ if (toksSize >= 6) { // property name-value pair(s)
+ for (unsigned i=5; i<toksSize; i++) {
+ nvPair propNvp = splitNameValuePair(toks[i]);
+ if (propNvp.second.size() == 0) {
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Badly formed property name-value pair \"" << propNvp.first << "\". (Must be name=value)";
+ return false;
+ }
+ Property prop;
+ try {
+ prop = AclHelper::getProperty(propNvp.first);
+ } catch (...) {
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Unknown property \"" << propNvp.first << "\".";
+ return false;
+ }
+ rule->addProperty(prop, propNvp.second);
+ }
+ }
+ // Check if name (toks[2]) is group; if not, add as name of individual
+ if (toks[2].compare("all") != 0) {
+ if (groups.find(toks[2]) == groups.end()) {
+ addName(toks[2]);
+ }
+ }
+
+ // If rule validates, add to rule list
+ if (!rule->validate(validationMap)) {
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Invalid object/action/property combination.";
+ return false;
+ }
+ rules.push_back(rule);
+
+ return true;
+}
+
+// Debug aid
+void AclReader::printRules() const {
+ QPID_LOG(debug, "Rule list: " << rules.size() << " ACL rules found:");
+ int cnt = 0;
+ for (rlCitr i=rules.begin(); i<rules.end(); i++,cnt++) {
+ QPID_LOG(debug, " " << std::setfill(' ') << std::setw(2) << cnt << " " << (*i)->toString());
+ }
+}
+
+// Static function
+// Return true if the name is well-formed (ie contains legal characters)
+bool AclReader::checkName(const std::string& name) {
+ for (unsigned i=0; i<name.size(); i++) {
+ const char ch = name.at(i);
+ if (!std::isalnum(ch) && ch != '-' && ch != '_' && ch != '@') return false;
+ }
+ return true;
+}
+
+// Static function
+// Split name-value pair around '=' char of the form "name=value"
+AclReader::nvPair AclReader::splitNameValuePair(const std::string& nvpString) {
+ std::size_t pos = nvpString.find("=");
+ if (pos == std::string::npos || pos == nvpString.size() - 1) {
+ return nvPair(nvpString, "");
+ }
+ return nvPair(nvpString.substr(0, pos), nvpString.substr(pos+1));
+}
+
+}} // namespace qpid::acl
diff --git a/RC9/qpid/cpp/src/qpid/acl/AclReader.h b/RC9/qpid/cpp/src/qpid/acl/AclReader.h
new file mode 100644
index 0000000000..d85dbeef6b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/acl/AclReader.h
@@ -0,0 +1,117 @@
+#ifndef QPID_ACL_ACLREADER_H
+#define QPID_ACL_ACLREADER_H
+
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <boost/shared_ptr.hpp>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+#include <sstream>
+#include "qpid/acl/AclData.h"
+#include "qpid/broker/AclModule.h"
+
+namespace qpid {
+namespace acl {
+
+class AclReader {
+ typedef std::set<std::string> nameSet;
+ typedef nameSet::const_iterator nsCitr;
+ typedef boost::shared_ptr<nameSet> nameSetPtr;
+
+ typedef std::pair<std::string, nameSetPtr> groupPair;
+ typedef std::map<std::string, nameSetPtr> groupMap;
+ typedef groupMap::const_iterator gmCitr;
+ typedef std::pair<gmCitr, bool> gmRes;
+
+ typedef std::pair<Property, std::string> propNvPair;
+ typedef std::map<Property, std::string> propMap;
+ typedef propMap::const_iterator pmCitr;
+
+ class aclRule {
+ public:
+ enum objectStatus {NONE, VALUE, ALL};
+ AclResult res;
+ nameSet names;
+ bool actionAll; // True if action is set to keyword "all"
+ Action action; // Ignored if action is set to keyword "all"
+ objectStatus objStatus;
+ ObjectType object; // Ignored for all status values except VALUE
+ propMap props;
+ public:
+ aclRule(const AclResult r, const std::string n, const groupMap& groups); // action = "all"
+ aclRule(const AclResult r, const std::string n, const groupMap& groups, const Action a);
+ void setObjectType(const ObjectType o);
+ void setObjectTypeAll();
+ bool addProperty(const Property p, const std::string v);
+ bool validate(const AclHelper::objectMapPtr& validationMap);
+ std::string toString(); // debug aid
+ private:
+ void processName(const std::string& name, const groupMap& groups);
+ };
+ typedef boost::shared_ptr<aclRule> aclRulePtr;
+ typedef std::vector<aclRulePtr> ruleList;
+ typedef ruleList::const_iterator rlCitr;
+
+ typedef std::vector<std::string> tokList;
+ typedef tokList::const_iterator tlCitr;
+
+ typedef std::set<std::string> keywordSet;
+ typedef keywordSet::const_iterator ksCitr;
+ typedef std::pair<std::string, std::string> nvPair; // Name-Value pair
+
+ std::string fileName;
+ int lineNumber;
+ bool contFlag;
+ std::string groupName;
+ nameSet names;
+ groupMap groups;
+ ruleList rules;
+ AclHelper::objectMapPtr validationMap;
+ std::ostringstream errorStream;
+
+ public:
+ AclReader();
+ virtual ~AclReader();
+ int read(const std::string& fn, boost::shared_ptr<AclData> d);
+ std::string getError();
+
+ private:
+ bool processLine(char* line);
+ void loadDecisionData( boost::shared_ptr<AclData> d);
+ int tokenize(char* line, tokList& toks);
+
+ bool processGroupLine(tokList& toks, const bool cont);
+ gmCitr addGroup(const std::string& groupName);
+ void addName(const std::string& name, nameSetPtr groupNameSet);
+ void addName(const std::string& name);
+ void printNames() const; // debug aid
+
+ bool processAclLine(tokList& toks);
+ void printRules() const; // debug aid
+
+ static bool checkName(const std::string& name);
+ static nvPair splitNameValuePair(const std::string& nvpString);
+};
+
+}} // namespace qpid::acl
+
+#endif // QPID_ACL_ACLREADER_H
diff --git a/RC9/qpid/cpp/src/qpid/acl/management-schema.xml b/RC9/qpid/cpp/src/qpid/acl/management-schema.xml
new file mode 100644
index 0000000000..f4637253d0
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/acl/management-schema.xml
@@ -0,0 +1,44 @@
+<schema package="org.apache.qpid.acl">
+
+<!--
+ * Copyright (c) 2008 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+
+ <class name="Acl">
+ <property name="brokerRef" type="objId" references="org.apache.qpid.broker:Broker" access="RO" index="y" parentRef="y"/>
+ <property name="policyFile" type="sstr" access="RO" desc="Name of the policy file"/>
+ <property name="enforcingAcl" type="bool" access="RO" desc="Currently Enforcing ACL"/>
+ <property name="transferAcl" type="bool" access="RO" desc="Any transfer ACL rules in force"/>
+ <property name="lastAclLoad" type="absTime" access="RO" desc="Timestamp of last successful load of ACL"/>
+ <statistic name="aclDenyCount" type="count64" unit="request" desc="Number of ACL requests denied"/>
+
+ <method name="reloadACLFile" desc="Reload the ACL file"/>
+ </class>
+
+ <eventArguments>
+ <arg name="action" type="sstr"/>
+ <arg name="arguments" type="map"/>
+ <arg name="objectName" type="sstr"/>
+ <arg name="objectType" type="sstr"/>
+ <arg name="reason" type="sstr"/>
+ <arg name="userId" type="sstr"/>
+ </eventArguments>
+
+ <event name="allow" sev="inform" args="userId, action, objectType, objectName, arguments"/>
+ <event name="deny" sev="notice" args="userId, action, objectType, objectName, arguments"/>
+ <event name="fileLoaded" sev="inform" args="userId"/>
+ <event name="fileLoadFailed" sev="error" args="userId, reason"/>
+
+</schema>
diff --git a/RC9/qpid/cpp/src/qpid/agent/ManagementAgent.h b/RC9/qpid/cpp/src/qpid/agent/ManagementAgent.h
new file mode 100644
index 0000000000..c94291c9e7
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/agent/ManagementAgent.h
@@ -0,0 +1,162 @@
+#ifndef _qpid_agent_ManagementAgent_
+#define _qpid_agent_ManagementAgent_
+
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+#include "qpid/management/ManagementObject.h"
+#include "qpid/management/ManagementEvent.h"
+#include "qpid/management/Manageable.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/client/ConnectionSettings.h"
+
+namespace qpid {
+namespace management {
+
+class ManagementAgent
+{
+ public:
+
+ class Singleton {
+ public:
+ Singleton(bool disableManagement = false);
+ ~Singleton();
+ static ManagementAgent* getInstance();
+ private:
+ static sys::Mutex lock;
+ static bool disabled;
+ static int refCount;
+ static ManagementAgent* agent;
+ };
+
+ typedef enum {
+ SEV_EMERG = 0,
+ SEV_ALERT = 1,
+ SEV_CRIT = 2,
+ SEV_ERROR = 3,
+ SEV_WARN = 4,
+ SEV_NOTE = 5,
+ SEV_INFO = 6,
+ SEV_DEBUG = 7,
+ SEV_DEFAULT = 8
+ } severity_t;
+
+ ManagementAgent() {}
+ virtual ~ManagementAgent() {}
+
+ virtual int getMaxThreads() = 0;
+
+ // Connect to a management broker
+ //
+ // brokerHost - Hostname or IP address (dotted-quad) of broker.
+ //
+ // brokerPort - TCP port of broker.
+ //
+ // intervalSeconds - The interval (in seconds) that this agent shall use
+ // between broadcast updates to the broker.
+ //
+ // useExternalThread - If true, the thread of control used for callbacks
+ // must be supplied by the user of the object (via the
+ // pollCallbacks method).
+ //
+ // If false, callbacks shall be invoked on the management
+ // agent's thread. In this case, the callback implementations
+ // MUST be thread safe.
+ //
+ // storeFile - File where this process has read and write access. This
+ // file shall be used to store persistent state.
+ //
+ virtual void init(const std::string& brokerHost = "localhost",
+ uint16_t brokerPort = 5672,
+ uint16_t intervalSeconds = 10,
+ bool useExternalThread = false,
+ const std::string& storeFile = "",
+ const std::string& uid = "guest",
+ const std::string& pwd = "guest",
+ const std::string& mech = "PLAIN",
+ const std::string& proto = "tcp") = 0;
+
+ virtual void init(const client::ConnectionSettings& settings,
+ uint16_t intervalSeconds = 10,
+ bool useExternalThread = false,
+ const std::string& storeFile = "") = 0;
+
+ // Register a schema with the management agent. This is normally called by the
+ // package initializer generated by the management code generator.
+ //
+ virtual void
+ registerClass(const std::string& packageName,
+ const std::string& className,
+ uint8_t* md5Sum,
+ management::ManagementObject::writeSchemaCall_t schemaCall) = 0;
+
+ virtual void
+ registerEvent(const std::string& packageName,
+ const std::string& eventName,
+ uint8_t* md5Sum,
+ management::ManagementEvent::writeSchemaCall_t schemaCall) = 0;
+
+ // Add a management object to the agent. Once added, this object shall be visible
+ // in the greater management context.
+ //
+ // Please note that ManagementObject instances are not explicitly deleted from
+ // the management agent. When the core object represented by a management object
+ // is deleted, the "resourceDestroy" method on the management object must be called.
+ // It will then be reclaimed in due course by the management agent.
+ //
+ // Once a ManagementObject instance is added to the agent, the agent then owns the
+ // instance. The caller MUST NOT free the resources of the instance at any time.
+ // When it is no longer needed, invoke its "resourceDestroy" method and discard the
+ // pointer. This allows the management agent to report the deletion of the object
+ // in an orderly way.
+ //
+ virtual ObjectId addObject(ManagementObject* objectPtr, uint64_t persistId = 0) = 0;
+
+ //
+ //
+ virtual void raiseEvent(const ManagementEvent& event,
+ severity_t severity = SEV_DEFAULT) = 0;
+
+ // If "useExternalThread" was set to true in init, this method must
+ // be called to provide a thread for any pending method calls that have arrived.
+ // The method calls for ManagementObject instances shall be invoked synchronously
+ // during the execution of this method.
+ //
+ // callLimit may optionally be used to limit the number of callbacks invoked.
+ // if 0, no limit is imposed.
+ //
+ // The return value is the number of callbacks that remain queued after this
+ // call is complete. It can be used to determine whether or not further calls
+ // to pollCallbacks are necessary to clear the backlog. If callLimit is zero,
+ // the return value will also be zero.
+ //
+ virtual uint32_t pollCallbacks(uint32_t callLimit = 0) = 0;
+
+ // If "useExternalThread" was set to true in the constructor, this method provides
+ // a standard file descriptor that can be used in a select statement to signal that
+ // there are method callbacks ready (i.e. that "pollCallbacks" will result in at
+ // least one method call). When this fd is ready-for-read, pollCallbacks may be
+ // invoked. Calling pollCallbacks shall reset the ready-to-read state of the fd.
+ //
+ virtual int getSignalFd() = 0;
+};
+
+}}
+
+#endif /*!_qpid_agent_ManagementAgent_*/
diff --git a/RC9/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp b/RC9/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp
new file mode 100644
index 0000000000..1e2f4cdd78
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp
@@ -0,0 +1,906 @@
+
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+#include "qpid/management/Manageable.h"
+#include "qpid/management/ManagementObject.h"
+#include "qpid/log/Statement.h"
+#include "ManagementAgentImpl.h"
+#include <list>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <iostream>
+#include <fstream>
+
+
+using namespace qpid::client;
+using namespace qpid::framing;
+using namespace qpid::management;
+using namespace qpid::sys;
+using namespace std;
+using std::stringstream;
+using std::ofstream;
+using std::ifstream;
+using std::string;
+using std::cout;
+using std::endl;
+
+Mutex ManagementAgent::Singleton::lock;
+bool ManagementAgent::Singleton::disabled = false;
+ManagementAgent* ManagementAgent::Singleton::agent = 0;
+int ManagementAgent::Singleton::refCount = 0;
+
+ManagementAgent::Singleton::Singleton(bool disableManagement)
+{
+ Mutex::ScopedLock _lock(lock);
+ if (disableManagement && !disabled) {
+ disabled = true;
+ assert(refCount == 0); // can't disable after agent has been allocated
+ }
+ if (refCount == 0 && !disabled)
+ agent = new ManagementAgentImpl();
+ refCount++;
+}
+
+ManagementAgent::Singleton::~Singleton()
+{
+ Mutex::ScopedLock _lock(lock);
+ refCount--;
+ if (refCount == 0 && !disabled) {
+ delete agent;
+ agent = 0;
+ }
+}
+
+ManagementAgent* ManagementAgent::Singleton::getInstance()
+{
+ return agent;
+}
+
+const string ManagementAgentImpl::storeMagicNumber("MA02");
+
+ManagementAgentImpl::ManagementAgentImpl() :
+ extThread(false), writeFd(-1), readFd(-1),
+ initialized(false), connected(false), lastFailure("never connected"),
+ clientWasAdded(true), requestedBrokerBank(0), requestedAgentBank(0),
+ assignedBrokerBank(0), assignedAgentBank(0), bootSequence(0),
+ connThreadBody(*this), connThread(connThreadBody),
+ pubThreadBody(*this), pubThread(pubThreadBody)
+{
+}
+
+ManagementAgentImpl::~ManagementAgentImpl()
+{
+ connThreadBody.close();
+
+ // If the thread is doing work on the connection, we must wait for it to
+ // complete before shutting down.
+ if (!connThreadBody.isSleeping()) {
+ connThread.join();
+ }
+
+ // Release the memory associated with stored management objects.
+ {
+ Mutex::ScopedLock lock(agentLock);
+
+ moveNewObjectsLH();
+ for (ManagementObjectMap::iterator iter = managementObjects.begin ();
+ iter != managementObjects.end ();
+ iter++) {
+ ManagementObject* object = iter->second;
+ delete object;
+ }
+ managementObjects.clear();
+ }
+}
+
+void ManagementAgentImpl::init(const string& brokerHost,
+ uint16_t brokerPort,
+ uint16_t intervalSeconds,
+ bool useExternalThread,
+ const string& _storeFile,
+ const string& uid,
+ const string& pwd,
+ const string& mech,
+ const string& proto)
+{
+ client::ConnectionSettings settings;
+ settings.protocol = proto;
+ settings.host = brokerHost;
+ settings.port = brokerPort;
+ settings.username = uid;
+ settings.password = pwd;
+ settings.mechanism = mech;
+ init(settings, intervalSeconds, useExternalThread, _storeFile);
+}
+
+void ManagementAgentImpl::init(const client::ConnectionSettings& settings,
+ uint16_t intervalSeconds,
+ bool useExternalThread,
+ const std::string& _storeFile)
+{
+ interval = intervalSeconds;
+ extThread = useExternalThread;
+ storeFile = _storeFile;
+ nextObjectId = 1;
+
+ QPID_LOG(info, "QMF Agent Initialized: broker=" << settings.host << ":" << settings.port <<
+ " interval=" << intervalSeconds << " storeFile=" << _storeFile);
+ connectionSettings = settings;
+
+ // TODO: Abstract the socket calls for portability
+ if (extThread) {
+ int pair[2];
+ int result = socketpair(PF_LOCAL, SOCK_STREAM, 0, pair);
+ if (result == -1) {
+ return;
+ }
+ writeFd = pair[0];
+ readFd = pair[1];
+
+ // Set the readFd to non-blocking
+ int flags = fcntl(readFd, F_GETFL);
+ fcntl(readFd, F_SETFL, flags | O_NONBLOCK);
+ }
+
+ retrieveData();
+ bootSequence++;
+ if ((bootSequence & 0xF000) != 0)
+ bootSequence = 1;
+ storeData(true);
+
+ initialized = true;
+}
+
+void ManagementAgentImpl::registerClass(const string& packageName,
+ const string& className,
+ uint8_t* md5Sum,
+ management::ManagementObject::writeSchemaCall_t schemaCall)
+{
+ Mutex::ScopedLock lock(agentLock);
+ PackageMap::iterator pIter = findOrAddPackage(packageName);
+ addClassLocal(ManagementItem::CLASS_KIND_TABLE, pIter, className, md5Sum, schemaCall);
+}
+
+void ManagementAgentImpl::registerEvent(const string& packageName,
+ const string& eventName,
+ uint8_t* md5Sum,
+ management::ManagementObject::writeSchemaCall_t schemaCall)
+{
+ Mutex::ScopedLock lock(agentLock);
+ PackageMap::iterator pIter = findOrAddPackage(packageName);
+ addClassLocal(ManagementItem::CLASS_KIND_EVENT, pIter, eventName, md5Sum, schemaCall);
+}
+
+ObjectId ManagementAgentImpl::addObject(ManagementObject* object,
+ uint64_t persistId)
+{
+ Mutex::ScopedLock lock(addLock);
+ uint16_t sequence = persistId ? 0 : bootSequence;
+ uint64_t objectNum = persistId ? persistId : nextObjectId++;
+
+ ObjectId objectId(&attachment, 0, sequence, objectNum);
+
+ // TODO: fix object-id handling
+ object->setObjectId(objectId);
+ newManagementObjects[objectId] = object;
+ return objectId;
+}
+
+void ManagementAgentImpl::raiseEvent(const ManagementEvent& event, severity_t severity)
+{
+ Mutex::ScopedLock lock(agentLock);
+ Buffer outBuffer(eventBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+ uint8_t sev = (severity == SEV_DEFAULT) ? event.getSeverity() : (uint8_t) severity;
+ stringstream key;
+
+ key << "console.event." << assignedBrokerBank << "." << assignedAgentBank << "." <<
+ event.getPackageName() << "." << event.getEventName();
+
+ encodeHeader(outBuffer, 'e');
+ outBuffer.putShortString(event.getPackageName());
+ outBuffer.putShortString(event.getEventName());
+ outBuffer.putBin128(event.getMd5Sum());
+ outBuffer.putLongLong(uint64_t(Duration(now())));
+ outBuffer.putOctet(sev);
+ event.encode(outBuffer);
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
+ outBuffer.reset();
+ connThreadBody.sendBuffer(outBuffer, outLen, "qpid.management", key.str());
+}
+
+uint32_t ManagementAgentImpl::pollCallbacks(uint32_t callLimit)
+{
+ Mutex::ScopedLock lock(agentLock);
+
+ for (uint32_t idx = 0; callLimit == 0 || idx < callLimit; idx++) {
+ if (methodQueue.empty())
+ break;
+
+ QueuedMethod* item = methodQueue.front();
+ methodQueue.pop_front();
+ {
+ Mutex::ScopedUnlock unlock(agentLock);
+ Buffer inBuffer(const_cast<char*>(item->body.c_str()), item->body.size());
+ invokeMethodRequest(inBuffer, item->sequence, item->replyTo);
+ delete item;
+ }
+ }
+
+ uint8_t rbuf[100];
+ while (read(readFd, rbuf, 100) > 0) ; // Consume all signaling bytes
+ return methodQueue.size();
+}
+
+int ManagementAgentImpl::getSignalFd(void)
+{
+ return readFd;
+}
+
+void ManagementAgentImpl::startProtocol()
+{
+ char rawbuffer[512];
+ Buffer buffer(rawbuffer, 512);
+
+ connected = true;
+ encodeHeader(buffer, 'A');
+ buffer.putShortString("RemoteAgent [C++]");
+ systemId.encode (buffer);
+ buffer.putLong(requestedBrokerBank);
+ buffer.putLong(requestedAgentBank);
+ uint32_t length = buffer.getPosition();
+ buffer.reset();
+ connThreadBody.sendBuffer(buffer, length, "qpid.management", "broker");
+ QPID_LOG(trace, "SENT AttachRequest: reqBroker=" << requestedBrokerBank <<
+ " reqAgent=" << requestedAgentBank);
+}
+
+void ManagementAgentImpl::storeData(bool requested)
+{
+ if (!storeFile.empty()) {
+ ofstream outFile(storeFile.c_str());
+ uint32_t brokerBankToWrite = requested ? requestedBrokerBank : assignedBrokerBank;
+ uint32_t agentBankToWrite = requested ? requestedAgentBank : assignedAgentBank;
+
+ if (outFile.good()) {
+ outFile << storeMagicNumber << " " << brokerBankToWrite << " " <<
+ agentBankToWrite << " " << bootSequence << endl;
+ outFile.close();
+ }
+ }
+}
+
+void ManagementAgentImpl::retrieveData()
+{
+ if (!storeFile.empty()) {
+ ifstream inFile(storeFile.c_str());
+ string mn;
+
+ if (inFile.good()) {
+ inFile >> mn;
+ if (mn == storeMagicNumber) {
+ inFile >> requestedBrokerBank;
+ inFile >> requestedAgentBank;
+ inFile >> bootSequence;
+ }
+ inFile.close();
+ }
+ }
+}
+
+void ManagementAgentImpl::sendCommandComplete(string replyToKey, uint32_t sequence,
+ uint32_t code, string text)
+{
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ encodeHeader(outBuffer, 'z', sequence);
+ outBuffer.putLong(code);
+ outBuffer.putShortString(text);
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
+ outBuffer.reset();
+ connThreadBody.sendBuffer(outBuffer, outLen, "amq.direct", replyToKey);
+ QPID_LOG(trace, "SENT CommandComplete: seq=" << sequence << " code=" << code << " text=" << text);
+}
+
+void ManagementAgentImpl::handleAttachResponse(Buffer& inBuffer)
+{
+ Mutex::ScopedLock lock(agentLock);
+
+ assignedBrokerBank = inBuffer.getLong();
+ assignedAgentBank = inBuffer.getLong();
+
+ QPID_LOG(trace, "RCVD AttachResponse: broker=" << assignedBrokerBank << " agent=" << assignedAgentBank);
+
+ if ((assignedBrokerBank != requestedBrokerBank) ||
+ (assignedAgentBank != requestedAgentBank)) {
+ if (requestedAgentBank == 0) {
+ QPID_LOG(notice, "Initial object-id bank assigned: " << assignedBrokerBank << "." <<
+ assignedAgentBank);
+ } else {
+ QPID_LOG(warning, "Collision in object-id! New bank assigned: " << assignedBrokerBank <<
+ "." << assignedAgentBank);
+ }
+ storeData();
+ requestedBrokerBank = assignedBrokerBank;
+ requestedAgentBank = assignedAgentBank;
+ }
+
+ attachment.setBanks(assignedBrokerBank, assignedAgentBank);
+
+ // Bind to qpid.management to receive commands
+ connThreadBody.bindToBank(assignedBrokerBank, assignedAgentBank);
+
+ // Send package indications for all local packages
+ for (PackageMap::iterator pIter = packages.begin();
+ pIter != packages.end();
+ pIter++) {
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ encodeHeader(outBuffer, 'p');
+ encodePackageIndication(outBuffer, pIter);
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
+ outBuffer.reset();
+ connThreadBody.sendBuffer(outBuffer, outLen, "qpid.management", "broker");
+
+ // Send class indications for all local classes
+ ClassMap cMap = pIter->second;
+ for (ClassMap::iterator cIter = cMap.begin(); cIter != cMap.end(); cIter++) {
+ outBuffer.reset();
+ encodeHeader(outBuffer, 'q');
+ encodeClassIndication(outBuffer, pIter, cIter);
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
+ outBuffer.reset();
+ connThreadBody.sendBuffer(outBuffer, outLen, "qpid.management", "broker");
+ }
+ }
+}
+
+void ManagementAgentImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequence)
+{
+ Mutex::ScopedLock lock(agentLock);
+ string packageName;
+ SchemaClassKey key;
+
+ inBuffer.getShortString(packageName);
+ inBuffer.getShortString(key.name);
+ inBuffer.getBin128(key.hash);
+
+ QPID_LOG(trace, "RCVD SchemaRequest: package=" << packageName << " class=" << key.name);
+
+ PackageMap::iterator pIter = packages.find(packageName);
+ if (pIter != packages.end()) {
+ ClassMap& cMap = pIter->second;
+ ClassMap::iterator cIter = cMap.find(key);
+ if (cIter != cMap.end()) {
+ SchemaClass& schema = cIter->second;
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ encodeHeader(outBuffer, 's', sequence);
+ schema.writeSchemaCall(outBuffer);
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
+ outBuffer.reset();
+ connThreadBody.sendBuffer(outBuffer, outLen, "qpid.management", "broker");
+
+ QPID_LOG(trace, "SENT SchemaInd: package=" << packageName << " class=" << key.name);
+ }
+ }
+}
+
+void ManagementAgentImpl::handleConsoleAddedIndication()
+{
+ Mutex::ScopedLock lock(agentLock);
+ clientWasAdded = true;
+
+ QPID_LOG(trace, "RCVD ConsoleAddedInd");
+}
+
+void ManagementAgentImpl::invokeMethodRequest(Buffer& inBuffer, uint32_t sequence, string replyTo)
+{
+ string methodName;
+ string packageName;
+ string className;
+ uint8_t hash[16];
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ ObjectId objId(inBuffer);
+ inBuffer.getShortString(packageName);
+ inBuffer.getShortString(className);
+ inBuffer.getBin128(hash);
+ inBuffer.getShortString(methodName);
+
+ encodeHeader(outBuffer, 'm', sequence);
+
+ ManagementObjectMap::iterator iter = managementObjects.find(objId);
+ if (iter == managementObjects.end() || iter->second->isDeleted()) {
+ outBuffer.putLong (Manageable::STATUS_UNKNOWN_OBJECT);
+ outBuffer.putMediumString(Manageable::StatusText(Manageable::STATUS_UNKNOWN_OBJECT));
+ } else {
+ if ((iter->second->getPackageName() != packageName) ||
+ (iter->second->getClassName() != className)) {
+ outBuffer.putLong (Manageable::STATUS_INVALID_PARAMETER);
+ outBuffer.putMediumString(Manageable::StatusText (Manageable::STATUS_INVALID_PARAMETER));
+ }
+ else
+ try {
+ outBuffer.record();
+ iter->second->doMethod(methodName, inBuffer, outBuffer);
+ } catch(exception& e) {
+ outBuffer.restore();
+ outBuffer.putLong(Manageable::STATUS_EXCEPTION);
+ outBuffer.putMediumString(e.what());
+ }
+ }
+
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
+ outBuffer.reset();
+ connThreadBody.sendBuffer(outBuffer, outLen, "amq.direct", replyTo);
+}
+
+void ManagementAgentImpl::handleGetQuery(Buffer& inBuffer, uint32_t sequence, string replyTo)
+{
+ FieldTable ft;
+ FieldTable::ValuePtr value;
+
+ moveNewObjectsLH();
+
+ ft.decode(inBuffer);
+
+ QPID_LOG(trace, "RCVD GetQuery: map=" << ft);
+
+ value = ft.get("_class");
+ if (value.get() == 0 || !value->convertsTo<string>()) {
+ value = ft.get("_objectid");
+ if (value.get() == 0 || !value->convertsTo<string>())
+ return;
+
+ ObjectId selector(value->get<string>());
+ ManagementObjectMap::iterator iter = managementObjects.find(selector);
+ if (iter != managementObjects.end()) {
+ ManagementObject* object = iter->second;
+ Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ encodeHeader(outBuffer, 'g', sequence);
+ object->writeProperties(outBuffer);
+ object->writeStatistics(outBuffer, true);
+ outLen = MA_BUFFER_SIZE - outBuffer.available ();
+ outBuffer.reset ();
+ connThreadBody.sendBuffer(outBuffer, outLen, "amq.direct", replyTo);
+
+ QPID_LOG(trace, "SENT ObjectInd");
+ }
+ sendCommandComplete(replyTo, sequence);
+ return;
+ }
+
+ string className(value->get<string>());
+
+ for (ManagementObjectMap::iterator iter = managementObjects.begin();
+ iter != managementObjects.end();
+ iter++) {
+ ManagementObject* object = iter->second;
+ if (object->getClassName() == className) {
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ encodeHeader(outBuffer, 'g', sequence);
+ object->writeProperties(outBuffer);
+ object->writeStatistics(outBuffer, true);
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
+ outBuffer.reset();
+ connThreadBody.sendBuffer(outBuffer, outLen, "amq.direct", replyTo);
+
+ QPID_LOG(trace, "SENT ObjectInd");
+ }
+ }
+
+ sendCommandComplete(replyTo, sequence);
+}
+
+void ManagementAgentImpl::handleMethodRequest(Buffer& inBuffer, uint32_t sequence, string replyTo)
+{
+ if (extThread) {
+ Mutex::ScopedLock lock(agentLock);
+ string body;
+
+ inBuffer.getRawData(body, inBuffer.available());
+ methodQueue.push_back(new QueuedMethod(sequence, replyTo, body));
+ write(writeFd, "X", 1);
+ } else {
+ invokeMethodRequest(inBuffer, sequence, replyTo);
+ }
+
+ QPID_LOG(trace, "RCVD MethodRequest");
+}
+
+void ManagementAgentImpl::received(Message& msg)
+{
+ string data = msg.getData();
+ Buffer inBuffer(const_cast<char*>(data.c_str()), data.size());
+ uint8_t opcode;
+ uint32_t sequence;
+ string replyToKey;
+
+ framing::MessageProperties p = msg.getMessageProperties();
+ if (p.hasReplyTo()) {
+ const framing::ReplyTo& rt = p.getReplyTo();
+ replyToKey = rt.getRoutingKey();
+ }
+
+ if (checkHeader(inBuffer, &opcode, &sequence))
+ {
+ if (opcode == 'a') handleAttachResponse(inBuffer);
+ else if (opcode == 'S') handleSchemaRequest(inBuffer, sequence);
+ else if (opcode == 'x') handleConsoleAddedIndication();
+ else if (opcode == 'G') handleGetQuery(inBuffer, sequence, replyToKey);
+ else if (opcode == 'M') handleMethodRequest(inBuffer, sequence, replyToKey);
+ }
+}
+
+void ManagementAgentImpl::encodeHeader(Buffer& buf, uint8_t opcode, uint32_t seq)
+{
+ buf.putOctet('A');
+ buf.putOctet('M');
+ buf.putOctet('2');
+ buf.putOctet(opcode);
+ buf.putLong (seq);
+}
+
+bool ManagementAgentImpl::checkHeader(Buffer& buf, uint8_t *opcode, uint32_t *seq)
+{
+ if (buf.getSize() < 8)
+ return false;
+
+ uint8_t h1 = buf.getOctet();
+ uint8_t h2 = buf.getOctet();
+ uint8_t h3 = buf.getOctet();
+
+ *opcode = buf.getOctet();
+ *seq = buf.getLong();
+
+ return h1 == 'A' && h2 == 'M' && h3 == '2';
+}
+
+ManagementAgentImpl::PackageMap::iterator ManagementAgentImpl::findOrAddPackage(const string& name)
+{
+ PackageMap::iterator pIter = packages.find(name);
+ if (pIter != packages.end())
+ return pIter;
+
+ // No such package found, create a new map entry.
+ pair<PackageMap::iterator, bool> result =
+ packages.insert(pair<string, ClassMap>(name, ClassMap()));
+
+ if (connected) {
+ // Publish a package-indication message
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ encodeHeader(outBuffer, 'p');
+ encodePackageIndication(outBuffer, result.first);
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
+ outBuffer.reset();
+ connThreadBody.sendBuffer(outBuffer, outLen, "qpid.management", "schema.package");
+ }
+
+ return result.first;
+}
+
+void ManagementAgentImpl::moveNewObjectsLH()
+{
+ Mutex::ScopedLock lock(addLock);
+ for (ManagementObjectMap::iterator iter = newManagementObjects.begin();
+ iter != newManagementObjects.end();
+ iter++)
+ managementObjects[iter->first] = iter->second;
+ newManagementObjects.clear();
+}
+
+void ManagementAgentImpl::addClassLocal(uint8_t classKind,
+ PackageMap::iterator pIter,
+ const string& className,
+ uint8_t* md5Sum,
+ management::ManagementObject::writeSchemaCall_t schemaCall)
+{
+ SchemaClassKey key;
+ ClassMap& cMap = pIter->second;
+
+ key.name = className;
+ memcpy(&key.hash, md5Sum, 16);
+
+ ClassMap::iterator cIter = cMap.find(key);
+ if (cIter != cMap.end())
+ return;
+
+ // No such class found, create a new class with local information.
+ cMap.insert(pair<SchemaClassKey, SchemaClass>(key, SchemaClass(schemaCall, classKind)));
+}
+
+void ManagementAgentImpl::encodePackageIndication(Buffer& buf,
+ PackageMap::iterator pIter)
+{
+ buf.putShortString((*pIter).first);
+
+ QPID_LOG(trace, "SENT PackageInd: package=" << (*pIter).first);
+}
+
+void ManagementAgentImpl::encodeClassIndication(Buffer& buf,
+ PackageMap::iterator pIter,
+ ClassMap::iterator cIter)
+{
+ SchemaClassKey key = (*cIter).first;
+
+ buf.putOctet((*cIter).second.kind);
+ buf.putShortString((*pIter).first);
+ buf.putShortString(key.name);
+ buf.putBin128(key.hash);
+
+ QPID_LOG(trace, "SENT ClassInd: package=" << (*pIter).first << " class=" << key.name);
+}
+
+void ManagementAgentImpl::periodicProcessing()
+{
+#define BUFSIZE 65536
+ Mutex::ScopedLock lock(agentLock);
+ char msgChars[BUFSIZE];
+ uint32_t contentSize;
+ list<pair<ObjectId, ManagementObject*> > deleteList;
+
+ if (!connected)
+ return;
+
+ moveNewObjectsLH();
+
+ //
+ // Clear the been-here flag on all objects in the map.
+ //
+ for (ManagementObjectMap::iterator iter = managementObjects.begin();
+ iter != managementObjects.end();
+ iter++) {
+ ManagementObject* object = iter->second;
+ object->setFlags(0);
+ if (clientWasAdded) {
+ object->setForcePublish(true);
+ }
+ }
+
+ clientWasAdded = false;
+
+ //
+ // Process the entire object map.
+ //
+ for (ManagementObjectMap::iterator baseIter = managementObjects.begin();
+ baseIter != managementObjects.end();
+ baseIter++) {
+ ManagementObject* baseObject = baseIter->second;
+
+ //
+ // Skip until we find a base object requiring a sent message.
+ //
+ if (baseObject->getFlags() == 1 ||
+ (!baseObject->getConfigChanged() &&
+ !baseObject->getInstChanged() &&
+ !baseObject->getForcePublish() &&
+ !baseObject->isDeleted()))
+ continue;
+
+ Buffer msgBuffer(msgChars, BUFSIZE);
+ for (ManagementObjectMap::iterator iter = baseIter;
+ iter != managementObjects.end();
+ iter++) {
+ ManagementObject* object = iter->second;
+ if (baseObject->isSameClass(*object) && object->getFlags() == 0) {
+ object->setFlags(1);
+ if (object->getConfigChanged() || object->getInstChanged())
+ object->setUpdateTime();
+
+ if (object->getConfigChanged() || object->getForcePublish() || object->isDeleted()) {
+ encodeHeader(msgBuffer, 'c');
+ object->writeProperties(msgBuffer);
+ }
+
+ if (object->hasInst() && (object->getInstChanged() || object->getForcePublish())) {
+ encodeHeader(msgBuffer, 'i');
+ object->writeStatistics(msgBuffer);
+ }
+
+ if (object->isDeleted())
+ deleteList.push_back(pair<ObjectId, ManagementObject*>(iter->first, object));
+ object->setForcePublish(false);
+
+ if (msgBuffer.available() < (BUFSIZE / 2))
+ break;
+ }
+ }
+
+ contentSize = BUFSIZE - msgBuffer.available();
+ if (contentSize > 0) {
+ msgBuffer.reset();
+ stringstream key;
+ key << "console.obj." << assignedBrokerBank << "." << assignedAgentBank << "." <<
+ baseObject->getPackageName() << "." << baseObject->getClassName();
+ connThreadBody.sendBuffer(msgBuffer, contentSize, "qpid.management", key.str());
+ }
+ }
+
+ // Delete flagged objects
+ for (list<pair<ObjectId, ManagementObject*> >::reverse_iterator iter = deleteList.rbegin();
+ iter != deleteList.rend();
+ iter++) {
+ delete iter->second;
+ managementObjects.erase(iter->first);
+ }
+
+ deleteList.clear();
+
+ {
+ Buffer msgBuffer(msgChars, BUFSIZE);
+ encodeHeader(msgBuffer, 'h');
+ msgBuffer.putLongLong(uint64_t(Duration(now())));
+ stringstream key;
+ key << "console.heartbeat." << assignedBrokerBank << "." << assignedAgentBank;
+
+ contentSize = BUFSIZE - msgBuffer.available();
+ msgBuffer.reset();
+ connThreadBody.sendBuffer(msgBuffer, contentSize, "qpid.management", key.str());
+ }
+}
+
+void ManagementAgentImpl::ConnectionThread::run()
+{
+ static const int delayMin(1);
+ static const int delayMax(128);
+ static const int delayFactor(2);
+ int delay(delayMin);
+ string dest("qmfagent");
+
+ sessionId.generate();
+ queueName << "qmfagent-" << sessionId;
+
+ while (true) {
+ try {
+ if (agent.initialized) {
+ QPID_LOG(debug, "QMF Agent attempting to connect to the broker...");
+ connection.open(agent.connectionSettings);
+ session = connection.newSession(queueName.str());
+ subscriptions = new client::SubscriptionManager(session);
+
+ session.queueDeclare(arg::queue=queueName.str(), arg::autoDelete=true,
+ arg::exclusive=true);
+ session.exchangeBind(arg::exchange="amq.direct", arg::queue=queueName.str(),
+ arg::bindingKey=queueName.str());
+
+ subscriptions->subscribe(agent, queueName.str(), dest);
+ QPID_LOG(info, "Connection established with broker");
+ {
+ Mutex::ScopedLock _lock(connLock);
+ if (shutdown)
+ return;
+ operational = true;
+ agent.startProtocol();
+ try {
+ Mutex::ScopedUnlock _unlock(connLock);
+ subscriptions->run();
+ } catch (exception) {}
+
+ QPID_LOG(warning, "Connection to the broker has been lost");
+
+ operational = false;
+ agent.connected = false;
+ }
+ delay = delayMin;
+ connection.close();
+ delete subscriptions;
+ subscriptions = 0;
+ }
+ } catch (exception &e) {
+ if (delay < delayMax)
+ delay *= delayFactor;
+ QPID_LOG(debug, "Connection failed: exception=" << e.what());
+ }
+
+ {
+ Mutex::ScopedLock _lock(connLock);
+ if (shutdown)
+ return;
+ sleeping = true;
+ {
+ Mutex::ScopedUnlock _unlock(connLock);
+ ::sleep(delay);
+ }
+ sleeping = false;
+ if (shutdown)
+ return;
+ }
+ }
+}
+
+ManagementAgentImpl::ConnectionThread::~ConnectionThread()
+{
+}
+
+void ManagementAgentImpl::ConnectionThread::sendBuffer(Buffer& buf,
+ uint32_t length,
+ const string& exchange,
+ const string& routingKey)
+{
+ {
+ Mutex::ScopedLock _lock(connLock);
+ if (!operational)
+ return;
+ }
+
+ Message msg;
+ string data;
+
+ buf.getRawData(data, length);
+ msg.getDeliveryProperties().setRoutingKey(routingKey);
+ msg.getMessageProperties().setReplyTo(ReplyTo("amq.direct", queueName.str()));
+ msg.setData(data);
+ try {
+ session.messageTransfer(arg::content=msg, arg::destination=exchange);
+ } catch(exception& e) {
+ QPID_LOG(error, "Exception caught in sendBuffer: " << e.what());
+ // Bounce the connection
+ if (subscriptions)
+ subscriptions->stop();
+ }
+}
+
+void ManagementAgentImpl::ConnectionThread::bindToBank(uint32_t brokerBank, uint32_t agentBank)
+{
+ stringstream key;
+ key << "agent." << brokerBank << "." << agentBank;
+ session.exchangeBind(arg::exchange="qpid.management", arg::queue=queueName.str(),
+ arg::bindingKey=key.str());
+}
+
+void ManagementAgentImpl::ConnectionThread::close()
+{
+ {
+ Mutex::ScopedLock _lock(connLock);
+ shutdown = true;
+ }
+ if (subscriptions)
+ subscriptions->stop();
+}
+
+bool ManagementAgentImpl::ConnectionThread::isSleeping() const
+{
+ Mutex::ScopedLock _lock(connLock);
+ return sleeping;
+}
+
+
+void ManagementAgentImpl::PublishThread::run()
+{
+ while (true) {
+ ::sleep(agent.getInterval());
+ agent.periodicProcessing();
+ }
+}
diff --git a/RC9/qpid/cpp/src/qpid/agent/ManagementAgentImpl.h b/RC9/qpid/cpp/src/qpid/agent/ManagementAgentImpl.h
new file mode 100644
index 0000000000..53eb690ba8
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/agent/ManagementAgentImpl.h
@@ -0,0 +1,237 @@
+#ifndef _qpid_agent_ManagementAgentImpl_
+#define _qpid_agent_ManagementAgentImpl_
+
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+#include "ManagementAgent.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/ConnectionSettings.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/Session.h"
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/MessageListener.h"
+#include "qpid/sys/Thread.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/framing/Uuid.h"
+#include <iostream>
+#include <sstream>
+#include <deque>
+
+namespace qpid {
+namespace management {
+
+class ManagementAgentImpl : public ManagementAgent, public client::MessageListener
+{
+ public:
+
+ ManagementAgentImpl();
+ virtual ~ManagementAgentImpl();
+
+ //
+ // Methods from ManagementAgent
+ //
+ int getMaxThreads() { return 1; }
+ void init(const std::string& brokerHost = "localhost",
+ uint16_t brokerPort = 5672,
+ uint16_t intervalSeconds = 10,
+ bool useExternalThread = false,
+ const std::string& storeFile = "",
+ const std::string& uid = "guest",
+ const std::string& pwd = "guest",
+ const std::string& mech = "PLAIN",
+ const std::string& proto = "tcp");
+ void init(const client::ConnectionSettings& settings,
+ uint16_t intervalSeconds = 10,
+ bool useExternalThread = false,
+ const std::string& storeFile = "");
+ bool isConnected() { return connected; }
+ std::string& getLastFailure() { return lastFailure; }
+ void registerClass(const std::string& packageName,
+ const std::string& className,
+ uint8_t* md5Sum,
+ management::ManagementObject::writeSchemaCall_t schemaCall);
+ void registerEvent(const std::string& packageName,
+ const std::string& eventName,
+ uint8_t* md5Sum,
+ management::ManagementObject::writeSchemaCall_t schemaCall);
+ ObjectId addObject(management::ManagementObject* objectPtr, uint64_t persistId = 0);
+ void raiseEvent(const management::ManagementEvent& event, severity_t severity = SEV_DEFAULT);
+ uint32_t pollCallbacks(uint32_t callLimit = 0);
+ int getSignalFd();
+
+ uint16_t getInterval() { return interval; }
+ void periodicProcessing();
+
+ private:
+
+ struct SchemaClassKey {
+ std::string name;
+ uint8_t hash[16];
+ };
+
+ struct SchemaClassKeyComp {
+ bool operator() (const SchemaClassKey& lhs, const SchemaClassKey& rhs) const
+ {
+ if (lhs.name != rhs.name)
+ return lhs.name < rhs.name;
+ else
+ for (int i = 0; i < 16; i++)
+ if (lhs.hash[i] != rhs.hash[i])
+ return lhs.hash[i] < rhs.hash[i];
+ return false;
+ }
+ };
+
+ struct SchemaClass {
+ management::ManagementObject::writeSchemaCall_t writeSchemaCall;
+ uint8_t kind;
+
+ SchemaClass(const management::ManagementObject::writeSchemaCall_t call,
+ const uint8_t _kind) : writeSchemaCall(call), kind(_kind) {}
+ };
+
+ struct QueuedMethod {
+ QueuedMethod(uint32_t _seq, std::string _reply, std::string _body) :
+ sequence(_seq), replyTo(_reply), body(_body) {}
+
+ uint32_t sequence;
+ std::string replyTo;
+ std::string body;
+ };
+
+ typedef std::deque<QueuedMethod*> MethodQueue;
+ typedef std::map<SchemaClassKey, SchemaClass, SchemaClassKeyComp> ClassMap;
+ typedef std::map<std::string, ClassMap> PackageMap;
+
+ PackageMap packages;
+ AgentAttachment attachment;
+ management::ManagementObjectMap managementObjects;
+ management::ManagementObjectMap newManagementObjects;
+ MethodQueue methodQueue;
+
+ void received (client::Message& msg);
+
+ uint16_t interval;
+ bool extThread;
+ int writeFd;
+ int readFd;
+ uint64_t nextObjectId;
+ std::string storeFile;
+ sys::Mutex agentLock;
+ sys::Mutex addLock;
+ framing::Uuid systemId;
+ client::ConnectionSettings connectionSettings;
+ bool initialized;
+ bool connected;
+ std::string lastFailure;
+
+ bool clientWasAdded;
+ uint32_t requestedBrokerBank;
+ uint32_t requestedAgentBank;
+ uint32_t assignedBrokerBank;
+ uint32_t assignedAgentBank;
+ uint16_t bootSequence;
+
+ static const uint8_t DEBUG_OFF = 0;
+ static const uint8_t DEBUG_CONN = 1;
+ static const uint8_t DEBUG_PROTO = 2;
+ static const uint8_t DEBUG_PUBLISH = 3;
+
+# define MA_BUFFER_SIZE 65536
+ char outputBuffer[MA_BUFFER_SIZE];
+ char eventBuffer[MA_BUFFER_SIZE];
+
+ friend class ConnectionThread;
+ class ConnectionThread : public sys::Runnable
+ {
+ bool operational;
+ ManagementAgentImpl& agent;
+ framing::Uuid sessionId;
+ client::Connection connection;
+ client::Session session;
+ client::SubscriptionManager* subscriptions;
+ std::stringstream queueName;
+ mutable sys::Mutex connLock;
+ bool shutdown;
+ bool sleeping;
+ void run();
+ public:
+ ConnectionThread(ManagementAgentImpl& _agent) :
+ operational(false), agent(_agent), subscriptions(0),
+ shutdown(false), sleeping(false) {}
+ ~ConnectionThread();
+ void sendBuffer(qpid::framing::Buffer& buf,
+ uint32_t length,
+ const std::string& exchange,
+ const std::string& routingKey);
+ void bindToBank(uint32_t brokerBank, uint32_t agentBank);
+ void close();
+ bool isSleeping() const;
+ };
+
+ class PublishThread : public sys::Runnable
+ {
+ ManagementAgentImpl& agent;
+ void run();
+ public:
+ PublishThread(ManagementAgentImpl& _agent) : agent(_agent) {}
+ };
+
+ ConnectionThread connThreadBody;
+ sys::Thread connThread;
+ PublishThread pubThreadBody;
+ sys::Thread pubThread;
+
+ static const std::string storeMagicNumber;
+
+ void startProtocol();
+ void storeData(bool requested=false);
+ void retrieveData();
+ PackageMap::iterator findOrAddPackage(const std::string& name);
+ void moveNewObjectsLH();
+ void addClassLocal (uint8_t classKind,
+ PackageMap::iterator pIter,
+ const std::string& className,
+ uint8_t* md5Sum,
+ management::ManagementObject::writeSchemaCall_t schemaCall);
+ void encodePackageIndication (framing::Buffer& buf,
+ PackageMap::iterator pIter);
+ void encodeClassIndication (framing::Buffer& buf,
+ PackageMap::iterator pIter,
+ ClassMap::iterator cIter);
+ void encodeHeader (framing::Buffer& buf, uint8_t opcode, uint32_t seq = 0);
+ bool checkHeader (framing::Buffer& buf, uint8_t *opcode, uint32_t *seq);
+ void sendCommandComplete (std::string replyToKey, uint32_t sequence,
+ uint32_t code = 0, std::string text = std::string("OK"));
+ void handleAttachResponse (qpid::framing::Buffer& inBuffer);
+ void handlePackageRequest (qpid::framing::Buffer& inBuffer);
+ void handleClassQuery (qpid::framing::Buffer& inBuffer);
+ void handleSchemaRequest (qpid::framing::Buffer& inBuffer, uint32_t sequence);
+ void invokeMethodRequest (qpid::framing::Buffer& inBuffer, uint32_t sequence, std::string replyTo);
+ void handleGetQuery (qpid::framing::Buffer& inBuffer, uint32_t sequence, std::string replyTo);
+ void handleMethodRequest (qpid::framing::Buffer& inBuffer, uint32_t sequence, std::string replyTo);
+ void handleConsoleAddedIndication();
+};
+
+}}
+
+#endif /*!_qpid_agent_ManagementAgentImpl_*/
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/Array.cpp b/RC9/qpid/cpp/src/qpid/amqp_0_10/Array.cpp
new file mode 100644
index 0000000000..380e0f1f36
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/Array.cpp
@@ -0,0 +1,34 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "Array.h"
+
+namespace qpid {
+namespace amqp_0_10 {
+
+std::ostream& operator<<(std::ostream& o, const Array& a) {
+ std::ostream_iterator<UnknownType> i(o, " ");
+ o << "Array<" << typeName(a.getType()) << "[";
+ std::copy(a.begin(), a.end(), i);
+ o << "]";
+ return o;
+}
+
+}} // namespace qpid::amqp_0_10
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/Array.h b/RC9/qpid/cpp/src/qpid/amqp_0_10/Array.h
new file mode 100644
index 0000000000..6e8a419df7
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/Array.h
@@ -0,0 +1,124 @@
+#ifndef QPID_AMQP_0_10_ARRAY_H
+#define QPID_AMQP_0_10_ARRAY_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/amqp_0_10/TypeForCode.h"
+#include "qpid/amqp_0_10/CodeForType.h"
+#include "qpid/amqp_0_10/UnknownType.h"
+#include "qpid/amqp_0_10/exceptions.h"
+#include "qpid/amqp_0_10/Codec.h"
+#include <vector>
+#include <ostream>
+
+namespace qpid {
+namespace amqp_0_10 {
+
+template <class T> class ArrayDomain : public std::vector<T> {
+ public:
+ template <class S> void serialize(S& s) { s.split(*this); }
+
+ template <class S> void encode(S& s) const {
+ s(contentSize())(CodeForType<T>::value)(uint32_t(this->size()));
+ s(this->begin(), this->end());
+ }
+
+ void encode(Codec::Size& s) const { s.raw(0, contentSize() + 4/*size*/); }
+
+ template <class S> void decode(S& s) {
+ uint32_t size; uint8_t type; uint32_t count;
+ s(size);
+ typename S::ScopedLimit l(s, size);
+ s(type);
+ if (type != CodeForType<T>::value)
+ throw InvalidArgumentException(QPID_MSG("Array domain expected type " << CodeForType<T>::value << " but found " << type));
+ s(count);
+ this->resize(count);
+ s(this->begin(), this->end());
+ }
+
+ private:
+ uint32_t contentSize() const {
+ return Codec::size(this->begin(), this->end()) + sizeof(uint32_t) /*count*/ + sizeof(uint8_t) /*type*/;
+ }
+};
+
+template <class T>
+std::ostream& operator<<(std::ostream& o, const ArrayDomain<T>& ad) {
+ std::ostream_iterator<T> i(o, " ");
+ o << "Array<" << typeName(CodeForType<T>::value) << ">[";
+ std::copy(ad.begin(), ad.end(), i);
+ o << "]";
+ return o;
+}
+
+/** A non-domain array is represented as and array of UnknownType.
+ * Special case templat.
+ */
+template<> class ArrayDomain<UnknownType> : public std::vector<UnknownType> {
+ public:
+ ArrayDomain(uint8_t type_=0) : type(type_) {}
+
+ template <class S> void serialize(S& s) { s.split(*this); }
+
+ template <class S> void encode(S& s) const {
+ s(contentSize())(type)(uint32_t(this->size()));
+ s(this->begin(), this->end());
+ }
+
+ void encode(Codec::Size& s) const { s.raw(0, contentSize() + 4/*size*/); }
+
+ template <class S> void decode(S& s) {
+ uint32_t size; uint32_t count;
+ s(size);
+ typename S::ScopedLimit l(s, size);
+ s(type)(count);
+ this->clear();
+ this->resize(count, UnknownType(type));
+ s(this->begin(), this->end());
+ }
+
+ uint8_t getType() const { return type; }
+
+ private:
+ uint32_t contentSize() const {
+ return Codec::size(this->begin(), this->end()) + sizeof(uint32_t) /*count*/ + sizeof(uint8_t) /*type*/;
+ }
+ uint8_t type;
+};
+
+std::ostream& operator<<(std::ostream& o, const Array& a);
+
+// FIXME aconway 2008-04-08: hack to supress encoding of
+// command-fragments and in-doubt as there is a problem with the spec
+// (command-fragments does not have a one byte type code.)
+namespace session { class CommandFragment; }
+namespace dtx { class Xid; }
+
+template <> struct ArrayDomain<session::CommandFragment> : public Void {};
+template <> struct ArrayDomain<dtx::Xid> : public Void {};
+inline std::ostream& operator<<(std::ostream& o, const ArrayDomain<session::CommandFragment>&) { return o; }
+inline std::ostream& operator<<(std::ostream& o, const ArrayDomain<dtx::Xid>&) { return o; }
+
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_AMQP_0_10_ARRAY_H*/
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/Body.h b/RC9/qpid/cpp/src/qpid/amqp_0_10/Body.h
new file mode 100644
index 0000000000..c96931551c
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/Body.h
@@ -0,0 +1,55 @@
+#ifndef QPID_AMQP_0_10_BODY_H
+#define QPID_AMQP_0_10_BODY_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <string>
+#include <ostream>
+
+namespace qpid {
+namespace amqp_0_10 {
+
+/** Holds data from a body frame. */
+class Body {
+ public:
+ Body() {}
+ Body(size_t size_) : str(size_, '\0') {}
+ Body(const char* data_, size_t size_) : str(data_, size_) {}
+
+ size_t size() const { return str.size(); };
+ const char* data() const { return str.data(); }
+ char* data() { return const_cast<char*>(str.data()); }
+
+ template <class S> void serialize(S& s) { s.raw(data(), size()); }
+
+ private:
+ std::string str;
+
+ friend std::ostream& operator<<(std::ostream&, const Body&);
+};
+
+inline std::ostream& operator<<(std::ostream& o, const Body& b) {
+ return o << b.str.substr(0, 16) << "... (" << b.size() << ")";
+}
+
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_AMQP_0_10_BODY_H*/
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/Codec.h b/RC9/qpid/cpp/src/qpid/amqp_0_10/Codec.h
new file mode 100644
index 0000000000..5cad5cf4ed
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/Codec.h
@@ -0,0 +1,213 @@
+#ifndef QPID_AMQP_0_10_CODEC_H
+#define QPID_AMQP_0_10_CODEC_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "built_in_types.h"
+#include "qpid/Serializer.h"
+#include <boost/type_traits/is_integral.hpp>
+#include <boost/type_traits/is_float.hpp>
+#include <boost/type_traits/is_arithmetic.hpp>
+#include <boost/detail/endian.hpp>
+#include <boost/static_assert.hpp>
+#include <iterator>
+
+namespace qpid {
+namespace amqp_0_10 {
+
+template <class T> void reverse(T& t) {
+ char*p =reinterpret_cast<char*>(&t);
+ std::reverse(p, p+sizeof(T));
+}
+
+#ifdef BOOST_LITTLE_ENDIAN
+template <class T> void bigEndian(T& t) { reverse(t); }
+template <class T> void littleEndian(T&) {}
+#else
+template <class T> void littleEndian(T& t) { reverse(t); }
+template <class T> void bigEndian(T&) {}
+#endif
+
+/**
+ * AMQP 0-10 encoding and decoding.
+ */
+struct Codec {
+ /** Encode to an output byte iterator */
+ template <class OutIter>
+ class Encoder : public EncoderBase<Encoder<OutIter> >
+ {
+ public:
+ typedef EncoderBase<Encoder<OutIter> > Base;
+ typedef OutIter Iterator;
+
+ Encoder(OutIter o, size_t limit=Base::maxLimit()) : out(o) {
+ this->setLimit(limit);
+ }
+
+ using EncoderBase<Encoder<OutIter> >::operator();
+
+ Encoder& operator()(bool x) { raw(x); return *this;}
+ Encoder& operator()(char x) { raw(x); return *this; }
+ Encoder& operator()(int8_t x) { raw(x); return *this; }
+ Encoder& operator()(uint8_t x) { raw(x); return *this; }
+
+ Encoder& operator()(int16_t x) { return networkByteOrder(x); }
+ Encoder& operator()(int32_t x) { return networkByteOrder(x); }
+ Encoder& operator()(int64_t x) { return networkByteOrder(x); }
+
+ Encoder& operator()(uint16_t x) { return networkByteOrder(x); }
+ Encoder& operator()(uint32_t x) { return networkByteOrder(x); }
+ Encoder& operator()(uint64_t x) { return networkByteOrder(x); }
+
+ Encoder& operator()(float x) { return networkByteOrder(x); }
+ Encoder& operator()(double x) { return networkByteOrder(x); }
+
+ void raw(const void* p, size_t n) {
+ this->addBytes(n);
+ out = std::copy((const char*)p, (const char*)p+n, out);
+ }
+
+ void raw(char b) { this->addBytes(1); *out++=b; }
+
+ template <class T> Encoder& littleEnd(T x) {
+ littleEndian(x); raw(&x, sizeof(x)); return *this;
+ }
+
+ OutIter pos() const { return out; }
+
+ private:
+
+ template <class T> Encoder& networkByteOrder(T x) {
+ bigEndian(x); raw(&x, sizeof(x)); return *this;
+ }
+
+ OutIter out;
+ };
+
+ template <class InIter>
+ class Decoder : public DecoderBase<Decoder<InIter> > {
+ public:
+ typedef DecoderBase<Decoder<InIter> > Base;
+ typedef InIter Iterator;
+
+ Decoder(InIter i, size_t limit=Base::maxLimit()) : in(i) {
+ this->setLimit(limit);
+ }
+
+ using DecoderBase<Decoder<InIter> >::operator();
+
+ // FIXME aconway 2008-03-10: wrong encoding, need packing support
+ Decoder& operator()(bool& x) { raw((char&)x); return *this; }
+
+ Decoder& operator()(char& x) { raw((char&)x); return *this; }
+ Decoder& operator()(int8_t& x) { raw((char&)x); return *this; }
+ Decoder& operator()(uint8_t& x) { raw((char&)x); return *this; }
+
+ Decoder& operator()(int16_t& x) { return networkByteOrder(x); }
+ Decoder& operator()(int32_t& x) { return networkByteOrder(x); }
+ Decoder& operator()(int64_t& x) { return networkByteOrder(x); }
+
+ Decoder& operator()(uint16_t& x) { return networkByteOrder(x); }
+ Decoder& operator()(uint32_t& x) { return networkByteOrder(x); }
+ Decoder& operator()(uint64_t& x) { return networkByteOrder(x); }
+
+ Decoder& operator()(float& x) { return networkByteOrder(x); }
+ Decoder& operator()(double& x) { return networkByteOrder(x); }
+
+ void raw(void *p, size_t n) {
+ this->addBytes(n);
+ std::copy(in, in+n, (char*)p);
+ std::advance(in, n);
+ }
+
+ void raw(char &b) { this->addBytes(1); b=*in++; }
+
+ template <class T> Decoder& littleEnd(T& x) {
+ raw(&x, sizeof(x)); littleEndian(x); return *this;
+ }
+
+ InIter pos() const { return in; }
+
+ private:
+
+ template <class T> Decoder& networkByteOrder(T& x) {
+ raw(&x, sizeof(x)); bigEndian(x); return *this;
+ }
+
+ InIter in;
+ };
+
+
+ class Size : public EncoderBase<Size> {
+ public:
+ Size() : size(0) {}
+
+ operator size_t() const { return size; }
+
+ using EncoderBase<Size>::operator();
+
+ // FIXME aconway 2008-03-10: wrong encoding, need packing support
+ Size& operator()(bool x) { size += sizeof(x); return *this; }
+
+ Size& operator()(char x) { size += sizeof(x); return *this; }
+ Size& operator()(int8_t x) { size += sizeof(x); return *this; }
+ Size& operator()(uint8_t x) { size += sizeof(x); return *this; }
+
+ Size& operator()(int16_t x) { size += sizeof(x); return *this; }
+ Size& operator()(int32_t x) { size += sizeof(x); return *this; }
+ Size& operator()(int64_t x) { size += sizeof(x); return *this; }
+
+ Size& operator()(uint16_t x) { size += sizeof(x); return *this; }
+ Size& operator()(uint32_t x) { size += sizeof(x); return *this; }
+ Size& operator()(uint64_t x) { size += sizeof(x); return *this; }
+
+ Size& operator()(float x) { size += sizeof(x); return *this; }
+ Size& operator()(double x) { size += sizeof(x); return *this; }
+
+ // FIXME aconway 2008-04-03: optimize op()(Iter,Iter)
+ // for Iter with fixed-size value_type:
+ // distance(begin,end)*sizeof(value_type)
+
+ void raw(const void*, size_t n){ size += n; }
+
+ template <class T> Size& littleEnd(T) { size+= sizeof(T); return *this; }
+
+ private:
+ size_t size;
+ };
+
+ // FIXME aconway 2008-03-11: rename to encoder(), decoder()
+ template <class InIter> static Decoder<InIter> decode(const InIter &i) {
+ return Decoder<InIter>(i);
+ }
+
+ template <class OutIter> static Encoder<OutIter> encode(OutIter i) {
+ return Encoder<OutIter>(i);
+ }
+
+ template <class T> static size_t size(const T& x) { return Size()(x); }
+ template <class Iter> static size_t size(const Iter& a, const Iter& z) { return Size()(a,z); }
+};
+
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_AMQP_0_10_CODEC_H*/
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/Command.h b/RC9/qpid/cpp/src/qpid/amqp_0_10/Command.h
new file mode 100644
index 0000000000..0fe023e520
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/Command.h
@@ -0,0 +1,62 @@
+#ifndef QPID_AMQP_0_10_COMMAND_H
+#define QPID_AMQP_0_10_COMMAND_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Control.h"
+#include "qpid/amqp_0_10/structs.h"
+
+namespace qpid {
+namespace amqp_0_10 {
+
+struct CommandVisitor;
+struct ConstCommandVisitor;
+struct CommandHolder;
+struct Command
+ : public Action,
+ public Visitable<CommandVisitor, ConstCommandVisitor, CommandHolder>
+{
+ using Action::getCommand;
+ Command* getCommand() { return this; }
+ uint8_t getCode() const;
+ uint8_t getClassCode() const;
+ const char* getName() const;
+ const char* getClassName() const;
+
+ session::Header sessionHeader;
+};
+
+std::ostream& operator<<(std::ostream&, const Command&);
+
+template <class T>
+struct CommandPacker : Packer<T> {
+ CommandPacker(T& t) : Packer<T>(t) {}
+
+ template <class S> void serialize(S& s) {
+ s(this->data.sessionHeader);
+ Packer<T>::serialize(s);
+ }
+};
+
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_AMQP_0_10_COMMAND_H*/
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/CommmandPacker.h b/RC9/qpid/cpp/src/qpid/amqp_0_10/CommmandPacker.h
new file mode 100644
index 0000000000..51ebfe8186
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/CommmandPacker.h
@@ -0,0 +1,60 @@
+#ifndef QPID_AMQP_0_10_COMMMANDPACKER_H
+#define QPID_AMQP_0_10_COMMMANDPACKER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/amqp_0_10/structs.h"
+
+namespace qpid {
+namespace amqp_0_10 {
+
+/**
+ * Packer for commands - serialize session.header before pack bits.
+ */
+template <class T>
+class CommmandPacker : public Packer<T>
+{
+ public:
+ CommmandPacker(T& t) : Packer<T>(t) {}
+ template <class S> void serialize(S& s) { s.split(*this); }
+
+ template <class S> void encode(S& s) const {
+ s.sessionHeader(
+ Packer<T>::encode(s);
+ }
+
+ template <class S> void decode(S& s) {
+ Bits bits;
+ s.littleEnd(bits);
+ PackedDecoder<S, Bits> decode(s, bits);
+ data.serialize(decode);
+ }
+
+
+ protected:
+ T& data;
+
+
+};
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_AMQP_0_10_COMMMANDPACKER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/Connection.cpp b/RC9/qpid/cpp/src/qpid/amqp_0_10/Connection.cpp
new file mode 100644
index 0000000000..5b14d60ff5
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/Connection.cpp
@@ -0,0 +1,138 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "Connection.h"
+#include "qpid/log/Statement.h"
+#include "qpid/amqp_0_10/exceptions.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/framing/ProtocolInitiation.h"
+
+namespace qpid {
+namespace amqp_0_10 {
+
+using sys::Mutex;
+
+Connection::Connection(sys::OutputControl& o, const std::string& id, bool _isClient)
+ : frameQueueClosed(false), output(o), identifier(id), initialized(false), isClient(_isClient), buffered(0)
+{}
+
+void Connection::setInputHandler(std::auto_ptr<sys::ConnectionInputHandler> c) {
+ connection = c;
+}
+
+size_t Connection::decode(const char* buffer, size_t size) {
+ framing::Buffer in(const_cast<char*>(buffer), size);
+ if (isClient && !initialized) {
+ //read in protocol header
+ framing::ProtocolInitiation pi;
+ if (pi.decode(in)) {
+ //TODO: check the version is correct
+ QPID_LOG(trace, "RECV " << identifier << " INIT(" << pi << ")");
+ }
+ initialized = true;
+ }
+ framing::AMQFrame frame;
+ while(frame.decode(in)) {
+ QPID_LOG(trace, "RECV [" << identifier << "]: " << frame);
+ connection->received(frame);
+ }
+ return in.getPosition();
+}
+
+bool Connection::canEncode() {
+ if (!frameQueueClosed) connection->doOutput();
+ Mutex::ScopedLock l(frameQueueLock);
+ return (!isClient && !initialized) || !frameQueue.empty();
+}
+
+bool Connection::isClosed() const {
+ Mutex::ScopedLock l(frameQueueLock);
+ return frameQueueClosed;
+}
+
+size_t Connection::encode(const char* buffer, size_t size) {
+ { // Swap frameQueue data into workQueue to avoid holding lock while we encode.
+ Mutex::ScopedLock l(frameQueueLock);
+ assert(workQueue.empty());
+ workQueue.swap(frameQueue);
+ }
+ framing::Buffer out(const_cast<char*>(buffer), size);
+ if (!isClient && !initialized) {
+ framing::ProtocolInitiation pi(getVersion());
+ pi.encode(out);
+ initialized = true;
+ QPID_LOG(trace, "SENT " << identifier << " INIT(" << pi << ")");
+ }
+ size_t frameSize=0;
+ size_t encoded=0;
+ while (!workQueue.empty() && ((frameSize=workQueue.front().encodedSize()) <= out.available())) {
+ workQueue.front().encode(out);
+ QPID_LOG(trace, "SENT [" << identifier << "]: " << workQueue.front());
+ workQueue.pop_front();
+ encoded += frameSize;
+ if (workQueue.empty() && out.available() > 0) connection->doOutput();
+ }
+ assert(workQueue.empty() || workQueue.front().encodedSize() <= size);
+ if (!workQueue.empty() && workQueue.front().encodedSize() > size)
+ throw InternalErrorException(QPID_MSG("Frame too large for buffer."));
+ {
+ Mutex::ScopedLock l(frameQueueLock);
+ buffered -= encoded;
+ // Put back any frames we did not encode.
+ frameQueue.insert(frameQueue.begin(), workQueue.begin(), workQueue.end());
+ workQueue.clear();
+ }
+ return out.getPosition();
+}
+
+void Connection::activateOutput() { output.activateOutput(); }
+void Connection::giveReadCredit(int32_t credit) { output.giveReadCredit(credit); }
+
+void Connection::close() {
+ // Close the output queue.
+ Mutex::ScopedLock l(frameQueueLock);
+ frameQueueClosed = true;
+}
+
+void Connection::closed() {
+ connection->closed();
+}
+
+void Connection::send(framing::AMQFrame& f) {
+ {
+ Mutex::ScopedLock l(frameQueueLock);
+ if (!frameQueueClosed)
+ frameQueue.push_back(f);
+ buffered += f.encodedSize();
+ }
+ activateOutput();
+}
+
+framing::ProtocolVersion Connection::getVersion() const {
+ return framing::ProtocolVersion(0,10);
+}
+
+size_t Connection::getBuffered() const {
+ Mutex::ScopedLock l(frameQueueLock);
+ return buffered;
+}
+
+}} // namespace qpid::amqp_0_10
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/Connection.h b/RC9/qpid/cpp/src/qpid/amqp_0_10/Connection.h
new file mode 100644
index 0000000000..743a7de3aa
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/Connection.h
@@ -0,0 +1,76 @@
+#ifndef QPID_AMQP_0_10_CONNECTION_H
+#define QPID_AMQP_0_10_CONNECTION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/sys/ConnectionCodec.h"
+#include "qpid/sys/ConnectionInputHandler.h"
+#include "qpid/sys/ConnectionOutputHandler.h"
+#include "qpid/sys/Mutex.h"
+#include <boost/intrusive_ptr.hpp>
+#include <memory>
+#include <deque>
+
+namespace qpid {
+
+namespace sys {
+class ConnectionInputHandlerFactory;
+}
+
+namespace amqp_0_10 {
+
+class Connection : public sys::ConnectionCodec,
+ public sys::ConnectionOutputHandler
+{
+ typedef std::deque<framing::AMQFrame> FrameQueue;
+
+ FrameQueue frameQueue;
+ FrameQueue workQueue;
+ bool frameQueueClosed;
+ mutable sys::Mutex frameQueueLock;
+ sys::OutputControl& output;
+ std::auto_ptr<sys::ConnectionInputHandler> connection;
+ std::string identifier;
+ bool initialized;
+ bool isClient;
+ size_t buffered;
+
+ public:
+ Connection(sys::OutputControl&, const std::string& id, bool isClient);
+ void setInputHandler(std::auto_ptr<sys::ConnectionInputHandler> c);
+ size_t decode(const char* buffer, size_t size);
+ size_t encode(const char* buffer, size_t size);
+ bool isClosed() const;
+ bool canEncode();
+ void activateOutput();
+ void giveReadCredit(int32_t);
+ void closed(); // connection closed by peer.
+ void close(); // closing from this end.
+ void send(framing::AMQFrame&);
+ framing::ProtocolVersion getVersion() const;
+ size_t getBuffered() const;
+};
+
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_AMQP_0_10_CONNECTION_H*/
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/Control.h b/RC9/qpid/cpp/src/qpid/amqp_0_10/Control.h
new file mode 100644
index 0000000000..226f6f92a6
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/Control.h
@@ -0,0 +1,70 @@
+#ifndef QPID_AMQP_0_10_CONTROL_H
+#define QPID_AMQP_0_10_CONTROL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Struct.h"
+
+namespace qpid {
+namespace amqp_0_10 {
+
+struct Command;
+struct Control;
+
+struct Action { // Base for commands & controls
+ virtual ~Action() {}
+ virtual Command* getCommand() { return 0; }
+ virtual Control* getControl() { return 0; }
+
+ virtual const Command* getCommand() const {
+ return const_cast<Action*>(this)->getCommand();
+ }
+ virtual const Control* getControl() const {
+ return const_cast<Action*>(this)->getControl();
+ }
+ static const uint8_t SIZE=0;
+ static const uint8_t PACK=2;
+};
+
+struct ControlVisitor;
+struct ConstControlVisitor;
+struct ControlHolder;
+struct Control
+ : public Action,
+ public Visitable<ControlVisitor, ConstControlVisitor, ControlHolder>
+{
+ using Action::getControl;
+ Control* getControl() { return this; }
+ uint8_t getCode() const;
+ uint8_t getClassCode() const;
+ const char* getName() const;
+ const char* getClassName() const;
+};
+std::ostream& operator<<(std::ostream&, const Control&);
+
+template <SegmentType E> struct ActionType;
+template <> struct ActionType<CONTROL> { typedef Control type; };
+template <> struct ActionType<COMMAND> { typedef Command type; };
+
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_AMQP_0_10_CONTROL_H*/
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/Decimal.h b/RC9/qpid/cpp/src/qpid/amqp_0_10/Decimal.h
new file mode 100644
index 0000000000..50fc457c76
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/Decimal.h
@@ -0,0 +1,51 @@
+#ifndef TESTS_DECIMAL_H
+#define TESTS_DECIMAL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <ostream>
+
+namespace qpid {
+namespace amqp_0_10 {
+
+template <class E, class M> struct Decimal {
+ E exponent;
+ M mantissa;
+
+ Decimal(E exp=0, M man=0) : exponent(exp), mantissa(man) {}
+
+ bool operator==(const Decimal& d) const {
+ return exponent == d.exponent && mantissa == d.mantissa;
+ }
+
+ // TODO aconway 2008-02-20: We could provide arithmetic operators
+ // if anybody really cares about this type.
+
+ template <class S> void serialize(S& s) { s(exponent)(mantissa); }
+};
+
+template<class E, class M>
+inline std::ostream& operator<<(std::ostream& o, const Decimal<E,M>& d) {
+ return o << "Decimal{" << d.mantissa << "/10^" << (int)d.exponent << "}";
+}
+}}
+
+#endif /*!TESTS_DECIMAL_H*/
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/Exception.h b/RC9/qpid/cpp/src/qpid/amqp_0_10/Exception.h
new file mode 100644
index 0000000000..6d526c1706
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/Exception.h
@@ -0,0 +1,96 @@
+#ifndef QPID_AMQP_0_10_EXCEPTION_H
+#define QPID_AMQP_0_10_EXCEPTION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/Exception.h"
+#include "qpid/amqp_0_10/specification_fwd.h"
+
+namespace qpid {
+namespace amqp_0_10 {
+
+/**
+ * Raised when the connection is unexpectedly closed. Sessions with
+ * non-0 timeout may be available for re-attachment on another connection.
+ */
+struct ConnectionException : public qpid::Exception {
+ // FIXME aconway 2008-04-04: Merge qpid::ConnectionException
+ // into this when the old code is removed.
+ typedef connection::CloseCode Code;
+ ConnectionException(Code c, const std::string m)
+ : qpid::Exception(m), code(c) {}
+ Code code;
+};
+
+/**
+ * Raised when a session is unexpectedly detached for any reason, or
+ * if an attempt is made to use a session that is not attached.
+ */
+struct SessionException : public qpid::Exception {
+ // FIXME aconway 2008-04-04: should not have a code at this level.
+ // Leave in place till old preview code is gone.
+ SessionException(int /*code*/, const std::string& msg) : qpid::Exception(msg) {}
+};
+
+/** Raised when the state of a session has been destroyed */
+struct SessionDestroyedException : public SessionException {
+ // FIXME aconway 2008-04-04: should not have a code at this level.
+ // Leave in place till old preview code is gone.
+ SessionDestroyedException(int code, const std::string& msg) : SessionException(code, msg){}
+};
+
+/** Raised when a session is destroyed due to an execution.exception */
+struct SessionAbortedException : public SessionDestroyedException {
+ typedef execution::ErrorCode Code;
+ SessionAbortedException(Code c, const std::string m)
+ : SessionDestroyedException(c, m), code(c) {}
+ Code code;
+};
+
+/**
+ * Raised when a session with 0 timeout is unexpectedly detached
+ * and therefore expires and is destroyed.
+ */
+struct SessionExpiredException : public SessionDestroyedException {
+ typedef session::DetachCode Code;
+ SessionExpiredException(Code c, const std::string m)
+ : SessionDestroyedException(c, m), code(c) {}
+ Code code;
+};
+
+/**
+ * Raised when a session with non-0 timeout is unexpectedly detached
+ * or if an attempt is made to use a session that is not attached.
+ *
+ * The session is not necessarily destroyed, it may be possible to
+ * re-attach.
+ */
+struct SessionDetachedException : public SessionException {
+ typedef session::DetachCode Code;
+ SessionDetachedException(Code c, const std::string m)
+ : SessionException(c, m), code(c) {}
+ Code code;
+};
+
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_AMQP_0_10_EXCEPTION_H*/
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/FrameHeader.cpp b/RC9/qpid/cpp/src/qpid/amqp_0_10/FrameHeader.cpp
new file mode 100644
index 0000000000..f1a59b9e27
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/FrameHeader.cpp
@@ -0,0 +1,50 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "FrameHeader.h"
+#include <ios>
+#include <iomanip>
+#include <ostream>
+
+using namespace std;
+
+namespace qpid {
+namespace amqp_0_10 {
+
+bool FrameHeader::operator==(const FrameHeader& x) const {
+ return flags == x.flags &&
+ type == x.type &&
+ size == x.size &&
+ track == x.track &&
+ channel == x.channel;
+}
+
+std::ostream& operator<<(std::ostream& o, const FrameHeader& f) {
+ std::ios::fmtflags saveFlags = o.flags();
+ return o << "Frame["
+ << "flags=" << std::hex << std::showbase << int(f.getFlags()) << std::setiosflags(saveFlags)
+ << " type=" << f.getType()
+ << " size=" << f.getSize()
+ << " track=" << int(f.getTrack())
+ << " channel=" << f.getChannel()
+ << "]";
+}
+
+}} // namespace qpid::amqp_0_10
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/FrameHeader.h b/RC9/qpid/cpp/src/qpid/amqp_0_10/FrameHeader.h
new file mode 100644
index 0000000000..b2f0619f9b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/FrameHeader.h
@@ -0,0 +1,90 @@
+#ifndef QPID_AMQP_0_10_FRAMEHEADER_H
+#define QPID_AMQP_0_10_FRAMEHEADER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/amqp_0_10/built_in_types.h"
+#include <boost/shared_array.hpp>
+#include <string.h>
+#include <assert.h>
+#include <iosfwd>
+
+namespace qpid {
+namespace amqp_0_10 {
+
+enum FrameFlags { FIRST_SEGMENT=8, LAST_SEGMENT=4, FIRST_FRAME=2, LAST_FRAME=1 };
+
+class FrameHeader {
+ public:
+ static const size_t SIZE=12;
+ static uint8_t trackFor(SegmentType type) { return type == 0 ? 0 : 1; }
+
+ FrameHeader(uint8_t flags_=0, SegmentType type_=SegmentType(), uint16_t size_=0, uint8_t track_=0, uint16_t channel_=0)
+ : flags(flags_), type(type_), size(size_), track(track_), channel(channel_)
+ {}
+
+ uint8_t getFlags() const { return flags; }
+ SegmentType getType() const { return type; }
+ /** @return size total size of of frame, including frame header. */
+ uint16_t getSize() const { return size; }
+ /** @return size of frame data, excluding frame header. */
+ uint16_t getDataSize() const { return size - SIZE; }
+ uint8_t getTrack() const { return track; }
+ uint16_t getChannel() const { return channel; }
+
+ void setFlags(uint8_t flags_) { flags=flags_; }
+ /** Also sets the track. There is no setTrack() */
+ void setType(SegmentType type_) { type=type_; track=trackFor(type); }
+ /** @param size total size of of frame, including frame header. */
+ void setSize(uint16_t size_) { size = size_; }
+ /** @param size size of frame data, excluding frame header. */
+ void setDataSize(uint16_t size_) { size = size_+SIZE; }
+ void setChannel(uint8_t channel_) { channel=channel_; }
+
+ bool allFlags(uint8_t f) const { return (flags & f) == f; }
+ bool anyFlags(uint8_t f) const { return (flags & f); }
+
+ void raiseFlags(uint8_t f) { flags |= f; }
+ void clearFlags(uint8_t f) { flags &= ~f; }
+
+ bool isComplete() const { return allFlags(FIRST_FRAME | LAST_FRAME); }
+
+ bool operator==(const FrameHeader&) const;
+
+ template <class S> void serialize(S& s) {
+ uint8_t pad8=0; uint32_t pad32=0;
+ s(flags)(type)(size)(pad8)(track)(channel)(pad32);
+ }
+
+ private:
+ uint8_t flags;
+ SegmentType type;
+ uint16_t size;
+ uint8_t track;
+ uint16_t channel;
+};
+
+std::ostream& operator<<(std::ostream&, const FrameHeader&);
+
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_AMQP_0_10_FRAMEHEADER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/Header.cpp b/RC9/qpid/cpp/src/qpid/amqp_0_10/Header.cpp
new file mode 100644
index 0000000000..669c960e7f
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/Header.cpp
@@ -0,0 +1,34 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "Header.h"
+
+namespace qpid {
+namespace amqp_0_10 {
+
+std::ostream& operator<<(std::ostream& o, const Header& h) {
+ o << "Header[";
+ std::ostream_iterator<Struct32> i(o, " ");
+ std::copy(h.begin(), h.end(), i);
+ o << "]";
+ return o;
+}
+
+}} // namespace qpid::amqp_0_10
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/Header.h b/RC9/qpid/cpp/src/qpid/amqp_0_10/Header.h
new file mode 100644
index 0000000000..0ce6ad9135
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/Header.h
@@ -0,0 +1,53 @@
+#ifndef QPID_AMQP_0_10_HEADER_H
+#define QPID_AMQP_0_10_HEADER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/amqp_0_10/built_in_types.h"
+#include "qpid/amqp_0_10/Struct32.h"
+#include <vector>
+#include <ostream>
+
+namespace qpid {
+namespace amqp_0_10 {
+
+class Header : public std::vector<Struct32> {
+ public:
+ Header() {}
+
+ template <class S> void serialize(S& s) { s.split(*this); }
+ template <class S> void encode(S& s) const { s(this->begin(), this->end()); }
+ template <class S> void decode(S& s);
+};
+
+template <class S> void Header::decode(S& s) {
+ this->clear();
+ while (s.bytesRemaining() > 0) {
+ this->push_back(Struct32());
+ s(this->back());
+ }
+}
+
+std::ostream& operator<<(std::ostream& o, const Header&);
+
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_AMQP_0_10_HEADER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/Holder.h b/RC9/qpid/cpp/src/qpid/amqp_0_10/Holder.h
new file mode 100644
index 0000000000..8712db6c86
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/Holder.h
@@ -0,0 +1,103 @@
+#ifndef QPID_AMQP_0_10_HOLDER_H
+#define QPID_AMQP_0_10_HOLDER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/framing/Blob.h"
+#include "apply.h"
+
+namespace qpid {
+namespace amqp_0_10 {
+
+using framing::in_place;
+
+template <class Invokable> struct InvokeVisitor {
+ typedef void result_type;
+ Invokable& target;
+ InvokeVisitor(Invokable& i) : target(i) {}
+
+ template <class Action>
+ void operator()(const Action& action) { action.invoke(target); }
+};
+
+template <class DerivedHolder, class BaseHeld, size_t Size>
+class Holder : public framing::Blob<Size, BaseHeld> {
+ typedef framing::Blob<Size, BaseHeld> Base;
+
+ public:
+
+ Holder() {}
+ template <class T> explicit Holder(const T& value) : Base(value) {}
+
+ using Base::operator=;
+ Holder& operator=(const BaseHeld& rhs);
+
+ uint8_t getCode() const { return this->get()->getCode(); }
+ uint8_t getClassCode() const { return this->get()->getClassCode(); }
+
+ template <class Invokable> void invoke(Invokable& i) const {
+ InvokeVisitor<Invokable> v(i);
+ apply(v, *this->get());
+ }
+
+ template <class S> void encode(S& s) const {
+ s(getClassCode())(getCode());
+ }
+
+ template <class S> void decode(S& s) {
+ uint8_t code, classCode;
+ s(classCode)(code);
+ static_cast<DerivedHolder*>(this)->set(classCode, code);
+ }
+
+ template <class S> void serialize(S& s) {
+ s.split(*this);
+ qpid::amqp_0_10::apply(s, *this->get());
+ }
+
+ template <class T> T* getIf() {
+ return (getClassCode()==T::CLASS_CODE && getCode()==T::CODE) ? static_cast<T*>(this->get()) : 0;
+ }
+
+ template <class T> const T* getIf() const {
+ return (getClassCode()==T::CLASS_CODE && getCode()==T::CODE) ? static_cast<T*>(this->get()) : 0;
+ }
+
+ private:
+ struct Assign : public ApplyFunctor<void> {
+ Holder& holder;
+ Assign(Holder& x) : holder(x) {}
+ template <class T> void operator()(const T& rhs) { holder=rhs; }
+ };
+};
+
+template <class D, class B, size_t S>
+Holder<D,B,S>& Holder<D,B,S>::operator=(const B& rhs) {
+ Assign assign(*this);
+ qpid::amqp_0_10::apply(assign, rhs);
+ return *this;
+}
+
+
+
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_AMQP_0_10_HOLDER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/Map.cpp b/RC9/qpid/cpp/src/qpid/amqp_0_10/Map.cpp
new file mode 100644
index 0000000000..b517b8baba
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/Map.cpp
@@ -0,0 +1,66 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "Map.h"
+#include "qpid/amqp_0_10/Struct32.h"
+#include "qpid/amqp_0_10/Array.h"
+#include <ostream>
+
+namespace qpid {
+namespace amqp_0_10 {
+
+MapValue::MapValue() : code(codeFor(uint8_t(0))), blob(in_place<uint8_t>(0)) {}
+
+MapValue::MapValue(const MapValue& x) : code(x.code), blob(x.blob) {}
+
+bool MapValue::operator==(const MapValue& x) const {
+ return code == x.code; // FIXME aconway 2008-04-01: incomplete
+}
+
+struct OstreamVisitor : public MapValue::Visitor<std::ostream&> {
+ std::ostream& out;
+ OstreamVisitor(std::ostream& o) : out(o) {}
+ template <class T> std::ostream& operator()(const T& t) {
+ return out << t;
+ }
+};
+
+std::ostream& operator<<(std::ostream& o, const MapValue& m) {
+ o << typeName(m.getCode()) << ":";
+ const_cast<MapValue&>(m).apply_visitor(OstreamVisitor(o));
+ return o;
+}
+
+std::ostream& operator<<(std::ostream& o, const Map::value_type& v) {
+ return o << v.first << "=" << v.second;
+}
+std::ostream& operator<<(std::ostream& o, const Map& map) {
+ o << "map[";
+ std::ostream_iterator<Map::value_type> i(o, " ");
+ std::copy(map.begin(), map.end(), i);
+ return o << "]";
+}
+
+uint32_t Map::contentSize() const {
+ // FIXME aconway 2008-04-03: preview to 0-10 mapping: +4 for count.
+ return /*4 +*/ Codec::Size()(begin(), end());
+}
+
+}} // namespace qpid::amqp_0_10
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/Map.h b/RC9/qpid/cpp/src/qpid/amqp_0_10/Map.h
new file mode 100644
index 0000000000..4093b1a0aa
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/Map.h
@@ -0,0 +1,188 @@
+#ifndef QPID_AMQP_0_10_MAP_H
+#define QPID_AMQP_0_10_MAP_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on ang
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/Exception.h"
+#include "qpid/amqp_0_10/built_in_types.h"
+#include "qpid/amqp_0_10/UnknownType.h"
+#include "qpid/amqp_0_10/CodeForType.h"
+#include "qpid/amqp_0_10/TypeForCode.h"
+#include "qpid/amqp_0_10/Codec.h"
+#include "qpid/framing/Blob.h"
+#include <map>
+#include <string>
+#include <iosfwd>
+
+namespace qpid {
+namespace amqp_0_10 {
+
+class Map;
+
+class MapValue {
+ public:
+ struct BadTypeException : public Exception {};
+
+ template <class R> struct Visitor { typedef R result_type; };
+
+ MapValue();
+ MapValue(const MapValue& x);
+ template <class T> explicit MapValue(const T& t);
+ template <class T> MapValue& operator=(const T& t);
+
+ template <class T> T* get();
+ template <class T> const T* get() const;
+
+ template <class V> typename V::result_type apply_visitor(V&);
+ template <class V> typename V::result_type apply_visitor(const V&);
+
+ uint8_t getCode() const { return code; }
+
+ bool operator==(const MapValue&) const;
+
+ template <class S> void serialize(S& s) { s(code); s.split(*this); }
+ template <class S> void encode(S& s) const {
+ const_cast<MapValue*>(this)->apply_visitor(s);
+ }
+ template <class S> void decode(S& s) {
+ DecodeVisitor<S> dv(blob, s);
+ qpid::amqp_0_10::apply_visitor(dv, code);
+ }
+
+
+ private:
+ // TODO aconway 2008-04-15: Estimate required size, we will get a
+ // compile error from static_assert in Blob.h if the estimate is too
+ // low. We can't use sizeof() directly because #include Struct32.h
+ // creates a circular dependency. Needs a better solution.
+ static const size_t SIZE=256;
+ typedef framing::Blob<SIZE> Blob;
+
+ template <class V> struct VisitVisitor;
+ template <class T> struct GetVisitor;
+ template <class D> struct DecodeVisitor;
+
+ uint8_t code;
+ Blob blob;
+};
+
+class Map : public std::map<Str8, MapValue> {
+ public:
+ template <class S> void serialize(S& s) { s.split(*this); }
+ template <class S> void encode(S& s) const;
+ // Shortcut calculation for size.
+ void encode(Codec::Size& s) const { s.raw(0, contentSize() + 4/*size*/); }
+
+ template <class S> void decode(S& s);
+
+ private:
+ uint32_t contentSize() const;
+};
+
+std::ostream& operator<<(std::ostream&, const MapValue&);
+std::ostream& operator<<(std::ostream&, const Map::value_type&);
+std::ostream& operator<<(std::ostream&, const Map&);
+
+using framing::in_place;
+
+template <class T> MapValue::MapValue(const T& t) : code(codeFor(t)), blob(in_place<t>()) {}
+
+template <class T> MapValue& MapValue::operator=(const T& t) {
+ code=codeFor(t);
+ blob=t;
+ return *this;
+}
+
+template <class V> struct MapValue::VisitVisitor {
+ typedef typename V::result_type result_type;
+ V& visitor;
+ Blob& blob;
+ VisitVisitor(V& v, Blob& b) : visitor(v), blob(b) {}
+
+ template <class T> result_type operator()(T*) {
+ return visitor(*reinterpret_cast<T*>(blob.get()));
+ }
+};
+
+template <class V> typename V::result_type MapValue::apply_visitor(V& v) {
+ VisitVisitor<V> visitor(v, blob);
+ return qpid::amqp_0_10::apply_visitor(visitor, code);
+}
+
+template <class R> struct MapValue::GetVisitor {
+ typedef R* result_type;
+ const MapValue::Blob& blob;
+
+ GetVisitor(const MapValue::Blob& b) : blob(b) {}
+
+ R* operator()(R& r) { return &r; }
+ template <class T> R* operator()(T&) { return 0; }
+};
+
+template <class D> struct MapValue::DecodeVisitor {
+ typedef void result_type;
+ MapValue::Blob& blob;
+ D& decoder;
+ DecodeVisitor(Blob& b, D& d) : blob(b), decoder(d) {}
+
+ template <class T> void operator()(T*) {
+ T t;
+ decoder(t);
+ blob = t;
+ }
+};
+
+template <class T> T* MapValue::get() { return apply_visitor(GetVisitor<T>(blob)); }
+template <class T> const T* MapValue::get() const { return apply_visitor(GetVisitor<const T>()); }
+
+template <class V> typename V::result_type MapValue::apply_visitor(const V& v) {
+ return apply_visitor(const_cast<V&>(v));
+}
+
+template <class S> void Map::encode(S& s) const {
+ // FIXME aconway 2008-04-03: replace preview mapping with 0-10 mapping:
+ // s(contentSize())(uint32_t(size())); // size, count
+ s(contentSize());
+ for (const_iterator i = begin(); i != end(); ++i)
+ s(i->first)(i->second); // key (type value)
+}
+
+template <class S> void Map::decode(S& s) {
+ uint32_t decodedSize /*, count*/;
+ // FIXME aconway 2008-04-03: replace preview mapping with 0-10 mapping:
+ // s(contentSize())(uint32_t(size())); // size, count
+ // s(decodedSize)(count);
+ s(decodedSize);
+ typename S::ScopedLimit l(s, decodedSize); // Make sure we don't overrun.
+ // FIXME aconway 2008-04-03: replace preview with 0-10:
+ // for ( ; count > 0; --count) {
+ while (s.bytesRemaining() > 0) {
+ key_type k; MapValue v;
+ s(k)(v);
+ insert(value_type(k,v));
+ }
+}
+
+
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_AMQP_0_10_MAP_H*/
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/Packer.h b/RC9/qpid/cpp/src/qpid/amqp_0_10/Packer.h
new file mode 100644
index 0000000000..c38e3a7efa
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/Packer.h
@@ -0,0 +1,195 @@
+#ifndef QPID_PACKER_H
+#define QPID_PACKER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <boost/optional.hpp>
+#include <boost/none.hpp>
+#include "qpid/amqp_0_10/built_in_types.h"
+
+namespace qpid {
+namespace amqp_0_10 {
+
+/** Serialization for optional values */
+template <class T> struct SerializableOptional {
+ boost::optional<T>& optional;
+ SerializableOptional(boost::optional<T>& x) : optional(x) {}
+ template <class S> void serialize(S& s) {
+ if (optional)
+ s(*optional);
+ }
+};
+
+}}
+
+
+namespace boost { // For argument dependent lookup.
+
+template <class T>
+qpid::amqp_0_10::SerializableOptional<T> serializable(boost::optional<T>& x) {
+ return qpid::amqp_0_10::SerializableOptional<T>(x);
+}
+
+} // namespace boost
+
+namespace qpid {
+namespace amqp_0_10 {
+
+/** "Encoder" that encodes a struct as a set of bit flags
+ * for all non-empty members.
+ */
+class PackBits {
+ public:
+ PackBits() : bit(1), bits(0) {}
+
+ void setBit(bool b) { if (b) bits |= bit; bit <<= 1; }
+ uint32_t getBits() { return bits; }
+
+ /** The bit is always set for non-optional values. */
+ template <class T>
+ PackBits& operator()(const T&) { setBit(1); return *this; }
+
+ /** For optional values the bit is set if the value is present. */
+ template <class T> PackBits& operator()(const boost::optional<T>& opt) {
+ setBit(opt); return *this;
+ }
+
+ /** Bits are special optional values */
+ PackBits& operator()(Bit b) { setBit(b); return *this; }
+
+ private:
+ uint32_t bit;
+ uint32_t bits;
+};
+
+/** Bit mask to encode a packable struct */
+template<class T> uint32_t packBits(const T& t) {
+ PackBits pack;
+ const_cast<T&>(t).serialize(pack);
+ return pack.getBits();
+}
+
+/** Decode members enabled by Bits */
+template <class Decoder, class Bits>
+class PackedDecoder {
+ public:
+ PackedDecoder(Decoder& d, Bits b) : decode(d), bits(b) {}
+
+ template <class T> PackedDecoder& operator()(T& t) {
+ if (bits & 1)
+ decode(t);
+ else
+ t = T();
+ // FIXME aconway 2008-04-10: When we have all optionals
+ // represented by boost::optional the line above should be:
+ // throw CommandInvalidException("A required value was omitted.");
+ bits >>= 1;
+ return *this;
+ }
+
+ template <class T> PackedDecoder& operator()(boost::optional<T>& opt) {
+ if (bits & 1) {
+ opt = T();
+ decode(*opt);
+ }
+ else
+ opt = boost::none;
+ bits >>= 1;
+ return *this;
+ }
+
+ private:
+ Decoder& decode;
+ Bits bits;
+};
+
+/** Metafunction to compute type to contain pack bits. */
+template <int Bytes> struct UintOfSize;
+template <> struct UintOfSize<1> { typedef uint8_t type; };
+template <> struct UintOfSize<2> { typedef uint16_t type; };
+template <> struct UintOfSize<4> { typedef uint32_t type; };
+
+/**
+ * Helper to serialize packed structs.
+ */
+template <class T> class Packer
+{
+ public:
+ typedef typename UintOfSize<T::PACK>::type Bits;
+
+ Packer(T& t) : data(t) {}
+
+ template <class S> void serialize(S& s) { s.split(*this); }
+
+ template <class S> void encode(S& s) const {
+ Bits bits = packBits(data);
+ s.littleEnd(bits);
+ data.serialize(s);
+ }
+
+ template <class S> void decode(S& s) {
+ Bits bits;
+ s.littleEnd(bits);
+ PackedDecoder<S, Bits> decode(s, bits);
+ data.serialize(decode);
+ }
+
+
+ protected:
+ T& data;
+};
+
+template <class T, uint8_t=T::SIZE> struct SizedPacker : public Packer<T> {
+ typedef typename UintOfSize<T::SIZE>::type Size;
+
+ SizedPacker(T& t) : Packer<T>(t) {}
+
+ template <class S> void serialize(S& s) {
+ s.split(*this);
+ }
+
+ template <class S> void encode(S& s) const {
+ Codec::Size sizer;
+ this->data.serialize(sizer);
+ Size size=size_t(sizer)+T::PACK; // Size with pack bits.
+ s(size);
+ Packer<T>::encode(s);
+ }
+
+ template <class S> void decode(S& s) {
+ Size size;
+ s(size);
+ typename S::ScopedLimit l(s, size);
+ Packer<T>::decode(s);
+ }
+
+};
+
+template <class T> struct SizedPacker<T,0> : public Packer<T> {
+ SizedPacker(T& t) : Packer<T>(t) {}
+};
+
+}} // namespace qpid::amqp_0_10
+
+
+
+#endif /*!QPID_PACKER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/SerializableString.h b/RC9/qpid/cpp/src/qpid/amqp_0_10/SerializableString.h
new file mode 100644
index 0000000000..485b7ca6a8
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/SerializableString.h
@@ -0,0 +1,62 @@
+#ifndef QPID_AMQP_0_10_SERIALIZABLESTRING_H
+#define QPID_AMQP_0_10_SERIALIZABLESTRING_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+namespace qpid {
+namespace amqp_0_10 {
+
+/** Template for length-prefixed strings/arrays.
+ * Unique parameter allows creation of distinct SerializableString
+ * types with the smae T/SizeType
+ */
+template <class T, class SizeType, int Unique=0>
+struct SerializableString : public std::basic_string<T> {
+ SerializableString() {}
+ template <class U> SerializableString(const U& u) : std::basic_string<T>(u) {}
+ template <class I> SerializableString(const I& i, const I& j) : std::basic_string<T>(i,j) {}
+
+ using std::basic_string<T>::operator=;
+
+ template <class S> void serialize(S& s) { s.split(*this); }
+
+ template <class S> void encode(S& s) const {
+ s(SizeType(this->size()))(this->begin(), this->end());
+ }
+
+ template <class S> void decode(S& s) {
+ SizeType newSize;
+ s(newSize);
+ this->resize(newSize);
+ s(this->begin(), this->end());
+ }
+};
+
+// TODO aconway 2008-02-29: separate ostream ops
+template <class T, class SizeType>
+std::ostream& operator<<(std::ostream& o, const SerializableString<T,SizeType>& s) {
+ const std::basic_string<T> str(s);
+ return o << str.c_str(); // TODO aconway 2008-02-29: why doesn't o<<str work?
+}
+
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_AMQP_0_10_SERIALIZABLESTRING_H*/
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/SessionHandler.cpp b/RC9/qpid/cpp/src/qpid/amqp_0_10/SessionHandler.cpp
new file mode 100644
index 0000000000..0e57e4b3f1
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/SessionHandler.cpp
@@ -0,0 +1,316 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+
+#include "SessionHandler.h"
+#include "qpid/SessionState.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/framing/AllInvoker.h"
+#include "qpid/framing/enum.h"
+#include "qpid/log/Statement.h"
+
+
+#include <boost/bind.hpp>
+
+namespace qpid {
+namespace amqp_0_10 {
+using namespace framing;
+using namespace std;
+
+SessionHandler::SessionHandler(FrameHandler* out, ChannelId ch)
+ : channel(ch, out), peer(channel), ignoring(false), sendReady(), receiveReady() {}
+
+SessionHandler::~SessionHandler() {}
+
+namespace {
+bool isSessionControl(AMQMethodBody* m) {
+ return m &&
+ m->amqpClassId() == SESSION_CLASS_ID;
+}
+bool isSessionDetachedControl(AMQMethodBody* m) {
+ return isSessionControl(m) &&
+ m->amqpMethodId() == SESSION_DETACHED_METHOD_ID;
+}
+
+session::DetachCode convert(uint8_t code) {
+ switch(code) {
+ case 0: return session::DETACH_CODE_NORMAL;
+ case 1: return session::DETACH_CODE_SESSION_BUSY;
+ case 2: return session::DETACH_CODE_TRANSPORT_BUSY;
+ case 3: return session::DETACH_CODE_NOT_ATTACHED;
+ case 4: default: return session::DETACH_CODE_UNKNOWN_IDS;
+ }
+}
+
+} // namespace
+
+void SessionHandler::checkAttached() {
+ if (!getState())
+ throw NotAttachedException(
+ QPID_MSG("Channel " << channel.get() << " is not attached"));
+ assert(getInHandler());
+ assert(channel.next);
+}
+
+void SessionHandler::invoke(const AMQMethodBody& m) {
+ framing::invoke(*this, m);
+}
+
+void SessionHandler::handleIn(AMQFrame& f) {
+ // Note on channel states: a channel is attached if session != 0
+ AMQMethodBody* m = f.getBody()->getMethod();
+ try {
+ if (ignoring && !isSessionDetachedControl(m))
+ return;
+ else if (isSessionControl(m))
+ invoke(*m);
+ else {
+ checkAttached();
+ if (!receiveReady)
+ throw IllegalStateException(QPID_MSG(getState()->getId() << ": Not ready to receive data"));
+ if (!getState()->receiverRecord(f))
+ return; // Ignore duplicates.
+ if (getState()->receiverNeedKnownCompleted())
+ sendCompletion();
+ getInHandler()->handle(f);
+ }
+ }
+ catch(const SessionException& e) {
+ QPID_LOG(error, "Execution exception: " << e.what());
+ framing::AMQP_AllProxy::Execution execution(channel);
+ AMQMethodBody* m = f.getMethod();
+ SequenceNumber commandId;
+ if (getState()) commandId = getState()->receiverGetCurrent();
+ execution.exception(e.code, commandId, m ? m->amqpClassId() : 0, m ? m->amqpMethodId() : 0, 0, e.what(), FieldTable());
+ detaching();
+ sendDetach();
+ }
+ catch(const ChannelException& e){
+ QPID_LOG(error, "Channel exception: " << e.what());
+ peer.detached(name, e.code);
+ }
+ catch(const ConnectionException& e) {
+ QPID_LOG(error, "Connection exception: " << e.what());
+ connectionException(e.code, e.getMessage());
+ }
+ catch(const std::exception& e) {
+ QPID_LOG(error, "Unexpected exception: " << e.what());
+ connectionException(connection::CLOSE_CODE_FRAMING_ERROR, e.what());
+ }
+}
+
+namespace {
+bool isControl(const AMQFrame& f) {
+ return f.getMethod() && f.getMethod()->type() == framing::SEGMENT_TYPE_CONTROL;
+}
+bool isCommand(const AMQFrame& f) {
+ return f.getMethod() && f.getMethod()->type() == framing::SEGMENT_TYPE_COMMAND;
+}
+} // namespace
+
+void SessionHandler::handleOut(AMQFrame& f) {
+ checkAttached();
+ if (!sendReady)
+ throw IllegalStateException(QPID_MSG(getState()->getId() << ": Not ready to send data"));
+ getState()->senderRecord(f);
+ if (isCommand(f) && getState()->senderNeedFlush()) {
+ peer.flush(false, false, true);
+ getState()->senderRecordFlush();
+ }
+ channel.handle(f);
+}
+
+void SessionHandler::checkName(const std::string& name) {
+ checkAttached();
+ if (name != getState()->getId().getName())
+ throw InvalidArgumentException(
+ QPID_MSG("Incorrect session name: " << name
+ << ", expecting: " << getState()->getId().getName()));
+}
+
+void SessionHandler::attach(const std::string& name_, bool force) {
+ // Save the name for possible session-busy exception. Session-busy
+ // can be thrown before we have attached the handler to a valid
+ // SessionState, and in that case we need the name to send peer.detached
+ name = name_;
+ if (getState() && name == getState()->getId().getName())
+ return; // Idempotent
+ if (getState())
+ throw TransportBusyException(
+ QPID_MSG("Channel " << channel.get() << " already attached to " << getState()->getId()));
+ setState(name, force);
+ QPID_LOG(debug, "Attached channel " << channel.get() << " to " << getState()->getId());
+ peer.attached(name);
+ if (getState()->hasState())
+ peer.flush(true, true, true);
+ else
+ sendCommandPoint(getState()->senderGetCommandPoint());
+}
+
+void SessionHandler::attached(const std::string& name) {
+ checkName(name);
+}
+
+void SessionHandler::detach(const std::string& name) {
+ checkName(name);
+ peer.detached(name, session::DETACH_CODE_NORMAL);
+ handleDetach();
+}
+
+void SessionHandler::detached(const std::string& name, uint8_t code) {
+ checkName(name);
+ ignoring = false;
+ if (code != session::DETACH_CODE_NORMAL)
+ channelException(convert(code), "session.detached from peer.");
+ else {
+ handleDetach();
+ }
+}
+
+void SessionHandler::handleDetach() {
+ sendReady = receiveReady = false;
+}
+
+void SessionHandler::requestTimeout(uint32_t t) {
+ checkAttached();
+ getState()->setTimeout(t);
+ peer.timeout(t);
+}
+
+void SessionHandler::timeout(uint32_t t) {
+ checkAttached();
+ getState()->setTimeout(t);
+}
+
+void SessionHandler::commandPoint(const SequenceNumber& id, uint64_t offset) {
+ checkAttached();
+ getState()->receiverSetCommandPoint(SessionPoint(id, offset));
+ if (!receiveReady) {
+ receiveReady = true;
+ readyToReceive();
+ }
+}
+
+void SessionHandler::expected(const SequenceSet& commands, const Array& /*fragments*/) {
+ checkAttached();
+ if (getState()->hasState()) { // Replay
+ if (commands.empty()) throw IllegalStateException(
+ QPID_MSG(getState()->getId() << ": has state but client is attaching as new session."));
+ // TODO aconway 2008-05-12: support replay of partial commands.
+ // Here we always round down to the last command boundary.
+ SessionPoint expectedPoint = commands.empty() ? SequenceNumber(0) : SessionPoint(commands.front(),0);
+ SessionState::ReplayRange replay = getState()->senderExpected(expectedPoint);
+ sendCommandPoint(expectedPoint);
+ std::for_each(replay.begin(), replay.end(), out); // replay
+ }
+ else
+ sendCommandPoint(getState()->senderGetCommandPoint());
+}
+
+void SessionHandler::confirmed(const SequenceSet& commands, const Array& /*fragments*/) {
+ checkAttached();
+ // Ignore non-contiguous confirmations.
+ if (!commands.empty() && commands.front() >= getState()->senderGetReplayPoint())
+ getState()->senderConfirmed(commands.rangesBegin()->last());
+}
+
+void SessionHandler::completed(const SequenceSet& commands, bool timelyReply) {
+ checkAttached();
+ getState()->senderCompleted(commands);
+ if (getState()->senderNeedKnownCompleted() || timelyReply) {
+ peer.knownCompleted(commands);
+ getState()->senderRecordKnownCompleted();
+ }
+}
+
+void SessionHandler::knownCompleted(const SequenceSet& commands) {
+ checkAttached();
+ getState()->receiverKnownCompleted(commands);
+}
+
+void SessionHandler::flush(bool expected, bool confirmed, bool completed) {
+ checkAttached();
+ if (expected) {
+ SequenceSet expectSet;
+ if (getState()->hasState())
+ expectSet.add(getState()->receiverGetExpected().command);
+ peer.expected(expectSet, Array());
+ }
+ if (confirmed) {
+ SequenceSet confirmSet;
+ if (!getState()->receiverGetUnknownComplete().empty())
+ confirmSet.add(getState()->receiverGetUnknownComplete().front(),
+ getState()->receiverGetReceived().command);
+ peer.confirmed(confirmSet, Array());
+ }
+ if (completed)
+ peer.completed(getState()->receiverGetUnknownComplete(), true);
+}
+
+void SessionHandler::gap(const SequenceSet& /*commands*/) {
+ throw NotImplementedException("session.gap not supported");
+}
+
+void SessionHandler::sendDetach()
+{
+ checkAttached();
+ ignoring = true;
+ peer.detach(getState()->getId().getName());
+}
+
+void SessionHandler::sendCompletion() {
+ checkAttached();
+ const SequenceSet& c = getState()->receiverGetUnknownComplete();
+ peer.completed(c, getState()->receiverNeedKnownCompleted());
+}
+
+void SessionHandler::sendAttach(bool force) {
+ checkAttached();
+ QPID_LOG(debug, "SessionHandler::sendAttach attach id=" << getState()->getId());
+ peer.attach(getState()->getId().getName(), force);
+ if (getState()->hasState())
+ peer.flush(true, true, true);
+ else
+ sendCommandPoint(getState()->senderGetCommandPoint());
+}
+
+void SessionHandler::sendCommandPoint(const SessionPoint& point) {
+ peer.commandPoint(point.command, point.offset);
+ if (!sendReady) {
+ sendReady = true;
+ readyToSend();
+ }
+}
+
+void SessionHandler::sendTimeout(uint32_t t) {
+ checkAttached();
+ peer.requestTimeout(t);
+}
+
+void SessionHandler::sendFlush() {
+ peer.flush(false, true, true);
+}
+
+bool SessionHandler::ready() const {
+ return sendReady && receiveReady;
+}
+
+
+}} // namespace qpid::broker
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/SessionHandler.h b/RC9/qpid/cpp/src/qpid/amqp_0_10/SessionHandler.h
new file mode 100644
index 0000000000..016de454cc
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/SessionHandler.h
@@ -0,0 +1,114 @@
+#ifndef QPID_AMQP_0_10_SESSIONHANDLER_H
+#define QPID_AMQP_0_10_SESSIONHANDLER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/framing/ChannelHandler.h"
+#include "qpid/framing/AMQP_AllProxy.h"
+#include "qpid/framing/AMQP_AllOperations.h"
+#include "qpid/SessionState.h"
+
+namespace qpid {
+
+
+namespace amqp_0_10 {
+
+/**
+ * Base SessionHandler with logic common to both client and broker.
+ *
+ * A SessionHandler is associated with a channel and can be attached
+ * to a session state.
+ */
+
+class SessionHandler : public framing::AMQP_AllOperations::SessionHandler,
+ public framing::FrameHandler::InOutHandler
+{
+ public:
+ SessionHandler(framing::FrameHandler* out=0, uint16_t channel=0);
+ ~SessionHandler();
+
+ void setChannel(uint16_t ch) { channel = ch; }
+ uint16_t getChannel() const { return channel.get(); }
+
+ void setOutHandler(framing::FrameHandler& h) { channel.next = &h; }
+
+ virtual SessionState* getState() = 0;
+ virtual framing::FrameHandler* getInHandler() = 0;
+
+ // Non-protocol methods, called locally to initiate some action.
+ void sendDetach();
+ void sendCompletion();
+ void sendAttach(bool force);
+ void sendTimeout(uint32_t t);
+ void sendFlush();
+
+ /** True if the handler is ready to send and receive */
+ bool ready() const;
+
+ // Protocol methods
+ void attach(const std::string& name, bool force);
+ void attached(const std::string& name);
+ void detach(const std::string& name);
+ void detached(const std::string& name, uint8_t code);
+
+ void requestTimeout(uint32_t t);
+ void timeout(uint32_t t);
+
+ void commandPoint(const framing::SequenceNumber& id, uint64_t offset);
+ void expected(const framing::SequenceSet& commands, const framing::Array& fragments);
+ void confirmed(const framing::SequenceSet& commands,const framing::Array& fragments);
+ void completed(const framing::SequenceSet& commands, bool timelyReply);
+ void knownCompleted(const framing::SequenceSet& commands);
+ void flush(bool expected, bool confirmed, bool completed);
+ void gap(const framing::SequenceSet& commands);
+
+ protected:
+ virtual void invoke(const framing::AMQMethodBody& m);
+
+ virtual void setState(const std::string& sessionName, bool force) = 0;
+ virtual void channelException(framing::session::DetachCode code, const std::string& msg) = 0;
+ virtual void connectionException(framing::connection::CloseCode code, const std::string& msg) = 0;
+ virtual void detaching() = 0;
+
+ // Notification of events
+ virtual void readyToSend() {}
+ virtual void readyToReceive() {}
+
+ virtual void handleDetach();
+ virtual void handleIn(framing::AMQFrame&);
+ virtual void handleOut(framing::AMQFrame&);
+
+ void checkAttached();
+ void checkName(const std::string& name);
+
+ framing::ChannelHandler channel;
+ framing::AMQP_AllProxy::Session peer;
+ bool ignoring;
+ bool sendReady, receiveReady;
+ std::string name;
+
+ private:
+ void sendCommandPoint(const SessionPoint&);
+};
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_AMQP_0_10_SESSIONHANDLER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/Struct.h b/RC9/qpid/cpp/src/qpid/amqp_0_10/Struct.h
new file mode 100644
index 0000000000..c0cea09c60
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/Struct.h
@@ -0,0 +1,60 @@
+#ifndef QPID_AMQP_0_10_STRUCT_H
+#define QPID_AMQP_0_10_STRUCT_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "built_in_types.h"
+#include <iosfwd>
+
+namespace qpid {
+namespace amqp_0_10 {
+
+// Base classes for complex types.
+
+template <class V, class CV, class H> struct Visitable {
+ typedef V Visitor;
+ typedef CV ConstVisitor;
+ typedef H Holder;
+
+ virtual ~Visitable() {}
+ virtual void accept(Visitor&) = 0;
+ virtual void accept(ConstVisitor&) const = 0;
+};
+
+
+// Note: only coded structs inherit from Struct.
+struct StructVisitor;
+struct ConstStructVisitor;
+struct StructHolder;
+struct Struct
+ : public Visitable<StructVisitor, ConstStructVisitor, StructHolder>
+{
+ uint8_t getCode() const;
+ uint8_t getPack() const;
+ uint8_t getSize() const;
+ uint8_t getClassCode() const;
+};
+std::ostream& operator<<(std::ostream&, const Struct&);
+
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_AMQP_0_10_STRUCT_H*/
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/Struct32.cpp b/RC9/qpid/cpp/src/qpid/amqp_0_10/Struct32.cpp
new file mode 100644
index 0000000000..541f02bcc4
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/Struct32.cpp
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Struct32.h"
+
+namespace qpid {
+namespace amqp_0_10 {
+
+Struct32::Struct32() {
+ // FIXME aconway 2008-04-16: this is only here to force a valid
+ // default-constructed Struct32 for serialize tests, clean up.
+ *this = in_place<message::MessageResumeResult>();
+}
+
+std::ostream& operator<<(std::ostream& o, const Struct32& s) {
+ return o << static_cast<const StructHolder&>(s);
+}
+
+}} // namespace qpid::amqp_0_10
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/Struct32.h b/RC9/qpid/cpp/src/qpid/amqp_0_10/Struct32.h
new file mode 100644
index 0000000000..2ed73e0b4c
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/Struct32.h
@@ -0,0 +1,64 @@
+#ifndef QPID_AMQP_0_10_STRUCT32_H
+#define QPID_AMQP_0_10_STRUCT32_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/amqp_0_10/StructHolder.h"
+
+namespace qpid {
+namespace amqp_0_10 {
+
+class Struct32 : public StructHolder
+{
+ public:
+ Struct32();
+
+ template <class T> explicit Struct32(const T& t) : StructHolder(t) {}
+
+ template <class S> void serialize(S& s) { s.split(*this); }
+
+ using StructHolder::operator=;
+
+ template <class S> void encode(S& s) const {
+ s(contentSize());
+ const_cast<Struct32*>(this)->StructHolder::serialize(s);
+ }
+
+ template <class S> void decode(S& s) {
+ uint32_t contentSz;
+ s(contentSz);
+ typename S::ScopedLimit l(s, contentSz);
+ StructHolder::serialize(s);
+ }
+
+ private:
+ uint32_t contentSize() const {
+ return Codec::size(static_cast<const StructHolder&>(*this));
+ }
+
+};
+
+std::ostream& operator<<(std::ostream&, const Struct32&);
+
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_AMQP_0_10_STRUCT32_H*/
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/Unit.cpp b/RC9/qpid/cpp/src/qpid/amqp_0_10/Unit.cpp
new file mode 100644
index 0000000000..75ea1c1b30
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/Unit.cpp
@@ -0,0 +1,65 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "Unit.h"
+#include "Codec.h"
+
+namespace qpid {
+namespace amqp_0_10 {
+
+void Unit::updateVariant() {
+ switch (header.getType()) {
+ case CONTROL: variant=ControlHolder(); break;
+ case COMMAND: variant=CommandHolder(); break;
+ case HEADER: variant=Header(); break;
+ case BODY: variant=Body(header.getDataSize()); break;
+ default: assert(0); // FIXME aconway 2008-04-14: exception?
+ }
+}
+
+struct GetTypeVisitor : public boost::static_visitor<SegmentType> {
+ SegmentType operator()(const CommandHolder& ) const { return COMMAND; }
+ SegmentType operator()(const ControlHolder& ) const { return CONTROL; }
+ SegmentType operator()(const Header& ) const { return HEADER; }
+ SegmentType operator()(const Body&) const { return BODY; }
+};
+
+struct GetFlagsVisitor : public boost::static_visitor<uint8_t> {
+ uint8_t operator()(const CommandHolder& ) const { return FIRST_FRAME|LAST_FRAME|FIRST_SEGMENT; }
+ uint8_t operator()(const ControlHolder& ) const { return FIRST_FRAME|LAST_FRAME|FIRST_SEGMENT; }
+ uint8_t operator()(const Header& ) const { return FIRST_FRAME|LAST_FRAME; }
+ uint8_t operator()(const Body&) const { return 0; }
+};
+
+void Unit::updateHeader(uint8_t flags) {
+ GetFlagsVisitor flagger;
+ header.setFlags(flags | variant.apply_visitor(flagger));
+ GetTypeVisitor getter;
+ header.setType(variant.apply_visitor(getter));
+ header.setDataSize(Codec::size(*this));
+ // track automatically set from type.
+ // no channel specified at this point.
+}
+
+std::ostream& operator<<(std::ostream& o, const Unit& u) {
+ return o << u.getHeader() << " " << u.variant.type().name() << "[" << u.variant << "]";
+}
+
+}} // namespace qpid::amqp_0_10
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/Unit.h b/RC9/qpid/cpp/src/qpid/amqp_0_10/Unit.h
new file mode 100644
index 0000000000..0229e07419
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/Unit.h
@@ -0,0 +1,82 @@
+#ifndef QPID_AMQP_0_10_UNIT_H
+#define QPID_AMQP_0_10_UNIT_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/amqp_0_10/ControlHolder.h"
+#include "qpid/amqp_0_10/CommandHolder.h"
+#include "qpid/amqp_0_10/Header.h"
+#include "qpid/amqp_0_10/Body.h"
+#include "qpid/amqp_0_10/FrameHeader.h"
+
+#include <boost/variant.hpp>
+#include <ostream>
+
+namespace qpid {
+namespace amqp_0_10 {
+
+/**
+ * A Unit contains a frame header and associated value.
+ * For all types except BODY the frame header is for a complete segment.
+ */
+class Unit {
+ public:
+ explicit Unit(const FrameHeader& h=FrameHeader()) : header(h) { updateVariant(); }
+
+ /**
+ *@param flags: is ORed with the required flags for type T.
+ */
+ template <class T>
+ explicit Unit(const T& t, uint8_t flags=0) : variant(t) { updateHeader(flags); }
+
+ void setHeader(FrameHeader& h) { header = h; updateVariant(); }
+ const FrameHeader& getHeader() const { return header; }
+
+ template<class T> const T* get() const { return boost::get<T>(&variant); }
+ template<class T> T* get() { return boost::get<T>(&variant); }
+ template<class T> Unit& operator=(const T& t) { variant=t; return *this; }
+
+ template <class V> typename V::result_type applyVisitor(V& v) const {
+ variant.apply_visitor(v);
+ }
+
+ template <class S> void serialize(S& s) { variant.apply_visitor(s); s.split(*this); }
+ template <class S> void encode(S&) const {}
+ template <class S> void decode(S&) { updateHeader(header.getFlags()); }
+
+ private:
+ typedef boost::variant<ControlHolder, CommandHolder, Header, Body> Variant;
+
+ void updateHeader(uint8_t flags);
+ void updateVariant();
+
+ Variant variant;
+ FrameHeader header;
+
+ friend std::ostream& operator<<(std::ostream& o, const Unit& u);
+};
+
+std::ostream& operator<<(std::ostream& o, const Unit& u);
+
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_AMQP_0_10_UNIT_H*/
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/UnitHandler.h b/RC9/qpid/cpp/src/qpid/amqp_0_10/UnitHandler.h
new file mode 100644
index 0000000000..93a8ce573a
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/UnitHandler.h
@@ -0,0 +1,35 @@
+#ifndef QPID_AMQP_0_10_UNITHANDLER_H
+#define QPID_AMQP_0_10_UNITHANDLER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/framing/Handler.h"
+
+namespace qpid {
+namespace amqp_0_10 {
+
+class Unit;
+typedef framing::Handler<const Unit&> UnitHandler;
+
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_AMQP_0_10_UNITHANDLER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/UnknownStruct.cpp b/RC9/qpid/cpp/src/qpid/amqp_0_10/UnknownStruct.cpp
new file mode 100644
index 0000000000..35445054c9
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/UnknownStruct.cpp
@@ -0,0 +1,34 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/amqp_0_10/StructVisitor.h"
+#include "qpid/amqp_0_10/UnknownStruct.h"
+
+namespace qpid {
+namespace amqp_0_10 {
+
+void UnknownStruct::accept(Visitor& v) { v.visit(*this); }
+void UnknownStruct::accept(ConstVisitor& v) const { v.visit(*this); }
+std::ostream& operator<<(std::ostream& o, const UnknownStruct& u) {
+ return o << "UnknownStruct[class=" << u.getClassCode() << " code=" << u.getCode() << "]";
+}
+
+}} // namespace qpid::amqp_0_10
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/UnknownStruct.h b/RC9/qpid/cpp/src/qpid/amqp_0_10/UnknownStruct.h
new file mode 100644
index 0000000000..1c66d8e6af
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/UnknownStruct.h
@@ -0,0 +1,55 @@
+#ifndef QPID_AMQP_0_10_UNKNOWNSTRUCT_H
+#define QPID_AMQP_0_10_UNKNOWNSTRUCT_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/amqp_0_10/Struct.h"
+#include <string>
+
+namespace qpid {
+namespace amqp_0_10 {
+
+class UnknownStruct : public Struct {
+ public:
+ static const uint8_t SIZE=4;
+ static const uint8_t PACK=2;
+
+ template <class S> void serialize(S& s) { s.split(*this); s(data.begin(), data.end()); }
+ template <class S> void encode(S&) const { }
+ template <class S> void decode(S& s) { data.resize(s.bytesRemaining()); }
+
+ UnknownStruct(uint8_t cc=0, uint8_t c=0) : classCode(cc), code(c) {}
+ void accept(Visitor&);
+ void accept(ConstVisitor&) const;
+
+ uint8_t getClassCode() const { return classCode; }
+ uint8_t getCode() const { return code; }
+
+ private:
+ uint8_t classCode, code;
+ std::string data;
+};
+
+std::ostream& operator<<(std::ostream&, const UnknownStruct&);
+
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_AMQP_0_10_UNKNOWNSTRUCT_H*/
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/UnknownType.cpp b/RC9/qpid/cpp/src/qpid/amqp_0_10/UnknownType.cpp
new file mode 100644
index 0000000000..844891d732
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/UnknownType.cpp
@@ -0,0 +1,56 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "UnknownType.h"
+#include <boost/range/iterator_range.hpp>
+#include <ostream>
+
+namespace qpid {
+namespace amqp_0_10 {
+
+UnknownType::Width UnknownType::WidthTable[16] = {
+ { 1, 0 },
+ { 2, 0 },
+ { 4, 0 },
+ { 8, 0 },
+ { 16, 0 },
+ { 32, 0 },
+ { 64, 0 },
+ { 128, 0 },
+ { 0, 1 },
+ { 0, 2 },
+ { 0, 4 },
+ { -1, -1 }, // Invalid
+ { 5, 0 },
+ { 9, 0 },
+ { -1, -1 }, // Invalid
+ { 0, 0 }
+};
+
+int UnknownType::fixed() const { return WidthTable[code>>4].fixed; }
+int UnknownType::variable() const { return WidthTable[code>>4].variable; }
+UnknownType::UnknownType(uint8_t c) : code(c) { data.resize(fixed()); }
+
+std::ostream& operator<<(std::ostream& o, const UnknownType& u) {
+ return o << boost::make_iterator_range(u.begin(), u.end()) << std::endl;
+}
+
+}} // namespace qpid::amqp_0_10
+
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/UnknownType.h b/RC9/qpid/cpp/src/qpid/amqp_0_10/UnknownType.h
new file mode 100644
index 0000000000..1e4aa04bf4
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/UnknownType.h
@@ -0,0 +1,87 @@
+#ifndef QPID_AMQP_0_10_UNKNOWNTYPE_H
+#define QPID_AMQP_0_10_UNKNOWNTYPE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <vector>
+#include <iosfwd>
+#include <stdint.h>
+
+namespace qpid {
+namespace amqp_0_10 {
+
+/** Encode/decode an unknown type based on typecode. */
+class UnknownType {
+ public:
+ UnknownType(uint8_t code=0);
+ uint8_t getCode() const { return code; }
+ /** Size of fixed type or 0 if not fixed/0-length. -1 invalid */
+ int fixed() const;
+ /** Bytes in size type for variable width. -1 invalid */
+ int variable() const;
+
+ typedef std::vector<char>::const_iterator const_iterator;
+ const_iterator begin() const { return data.begin(); }
+ const_iterator end() const { return data.end(); }
+ size_t size() const { return data.size(); }
+
+ template <class S> void serialize(S& s) { s.split(*this); }
+ template <class S> void encode(S& s) const;
+ template <class S> void decode(S& s);
+
+ private:
+ uint8_t code;
+ struct Width { int fixed; int variable; };
+ static Width WidthTable[16];
+
+ std::vector<char> data;
+};
+
+template <class S> void UnknownType::encode(S& s) const {
+ switch (variable()) {
+ case 0: break;
+ case 1: s(uint8_t(data.size())); break;
+ case 2: s(uint16_t(data.size())); break;
+ case 4: s(uint32_t(data.size())); break;
+ }
+ s(data.begin(), data.end());
+}
+
+template <class S> void UnknownType::decode(S& s) {
+ uint32_t s8;
+ uint32_t s16;
+ uint32_t s32;
+ switch (variable()) {
+ case 0: break;
+ case 1: s(s8); data.resize(s8); break;
+ case 2: s(s16); data.resize(s16); break;
+ case 4: s(s32); data.resize(s32); break;
+ }
+ s(data.begin(), data.end());
+}
+
+inline uint8_t codeFor(const UnknownType& u) { return u.getCode(); }
+
+std::ostream& operator<<(std::ostream&, const UnknownType&);
+
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_AMQP_0_10_UNKNOWNTYPE_H*/
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/apply.h b/RC9/qpid/cpp/src/qpid/amqp_0_10/apply.h
new file mode 100644
index 0000000000..f32b3482ef
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/apply.h
@@ -0,0 +1,86 @@
+#ifndef QPID_AMQP_0_10_APPLY_H
+#define QPID_AMQP_0_10_APPLY_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <boost/optional.hpp>
+
+namespace qpid {
+namespace amqp_0_10 {
+
+template <class F, class R=typename F::result_type> struct FunctionAndResult {
+ F* functor;
+ boost::optional<R> result;
+
+ FunctionAndResult() : functor(0) {}
+ template <class T> void invoke(T& t) { result=(*functor)(t); }
+ template <class T> void invoke(const T& t) { result=(*functor)(t); }
+ R getResult() { return *result; }
+};
+
+// void result is special case.
+template <class F> struct FunctionAndResult<F, void> {
+ F* functor;
+
+ FunctionAndResult() : functor(0) {}
+ template <class T> void invoke(T& t) { (*functor)(t); }
+ void getResult() {}
+};
+
+// Metafunction returning correct abstract visitor for Visitable type.
+template <class Visitable> struct VisitorType {
+ typedef typename Visitable::Visitor type;
+};
+template <class Visitable> struct VisitorType<const Visitable> {
+ typedef typename Visitable::ConstVisitor type;
+};
+
+template <class Visitor, class F>
+struct ApplyVisitorBase : public Visitor, public FunctionAndResult<F> {};
+
+// Specialize for each visitor type
+template <class Visitable, class F> struct ApplyVisitor;
+
+/** Apply a functor to a visitable object.
+ * The functor can have operator() overloads for each visitable type
+ * and/or templated operator().
+ */
+template <class F, class Visitable>
+typename F::result_type apply(F& functor, Visitable& visitable) {
+ ApplyVisitor<typename VisitorType<Visitable>::type, F> visitor;
+ visitor.functor=&functor;
+ visitable.accept(visitor);
+ return visitor.getResult();
+}
+
+template <class F, class Visitable>
+typename F::result_type apply(const F& functor, Visitable& visitable) {
+ ApplyVisitor<typename VisitorType<Visitable>::type, const F> visitor;
+ visitor.functor=&functor;
+ visitable.accept(visitor);
+ return visitor.getResult();
+}
+
+template <class R> struct ApplyFunctor { typedef R result_type; };
+
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_AMQP_0_10_APPLY_H*/
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/built_in_types.h b/RC9/qpid/cpp/src/qpid/amqp_0_10/built_in_types.h
new file mode 100644
index 0000000000..196e02a302
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/built_in_types.h
@@ -0,0 +1,171 @@
+#ifndef QPID_AMQP_0_10_BUILT_IN_TYPES_H
+#define QPID_AMQP_0_10_BUILT_IN_TYPES_H
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/Serializer.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/sys/IntegerTypes.h"
+#include "qpid/sys/Time.h"
+#include "Decimal.h"
+#include "SerializableString.h"
+#include <boost/array.hpp>
+#include <boost/range/iterator_range.hpp>
+#include <string>
+#include <ostream>
+#include <vector>
+
+/**@file Mapping from built-in AMQP types to C++ types */
+
+namespace qpid {
+
+namespace framing {
+class SequenceNumber;
+class SequenceSet;
+}
+
+namespace amqp_0_10 {
+
+/** Wrapper that behaves like type T but is a distinct type for
+ * overloading purposes. Unique allows multiple distinc wrappers.
+ */
+template <class T, int Unique=0> struct Wrapper {
+ T value;
+ Wrapper() {}
+ Wrapper(const T& x) : value(x) {}
+ Wrapper& operator=(const T& x) { value=x; return *this; }
+ operator T&() { return value; }
+ operator const T&() const { return value; }
+ template <class S> void serialize(S& s) { s(value); }
+};
+
+template<class T>
+inline std::ostream& operator<<(std::ostream& o, const Wrapper<T>& w) {
+ return o << w.value;
+}
+
+/** Void type */
+struct Void { template <class S> void serialize(S&) {} };
+inline std::ostream& operator<<(std::ostream& o, const Void&) { return o; }
+
+/** Bit is a presence indicator - an optional value with no encoding. */
+struct Bit : public Wrapper<bool> {
+ Bit(bool b=false) : Wrapper<bool>(b) {}
+ using Wrapper<bool>::operator=;
+ template <class S> void serialize(S& s) { s.split(*this); }
+ template <class S> void encode(S&) const { }
+ template <class S> void decode(S&) { *this = true; }
+};
+
+inline std::ostream& operator<<(std::ostream& o, const Bit& b) {
+ return o << bool(b);
+}
+
+// Fixed size types
+typedef bool Boolean;
+typedef char Char;
+typedef int8_t Int8;
+typedef int16_t Int16;
+typedef int32_t Int32;
+typedef int64_t Int64;
+typedef uint8_t Uint8;
+typedef uint16_t Uint16;
+typedef uint32_t Uint32;
+typedef uint64_t Uint64;
+typedef Wrapper<uint32_t> CharUtf32;
+
+template <size_t N> struct Bin : public boost::array<char, N> {
+ template <class S> void serialize(S& s) { s.raw(this->begin(), this->size()); }
+};
+
+template <size_t N> std::ostream& operator<<(std::ostream& o, const Bin<N>& b) {
+ return o << boost::make_iterator_range(b.begin(), b.end());
+}
+
+template <> struct Bin<1> : public boost::array<char, 1> {
+ Bin(char c=0) { this->front() = c; }
+ operator char() { return this->front(); }
+ template <class S> void serialize(S& s) { s(front()); }
+};
+
+typedef Bin<1> Bin8;
+typedef Bin<128> Bin1024;
+typedef Bin<16> Bin128;
+typedef Bin<2> Bin16;
+typedef Bin<32> Bin256;
+typedef Bin<4> Bin32;
+typedef Bin<5> Bin40;
+typedef Bin<64> Bin512;
+typedef Bin<8> Bin64;
+typedef Bin<9> Bin72;
+
+typedef double Double;
+typedef float Float;
+typedef framing::SequenceNumber SequenceNo;
+using framing::Uuid;
+typedef sys::AbsTime Datetime;
+
+typedef Decimal<Uint8, Int32> Dec32;
+typedef Decimal<Uint8, Int64> Dec64;
+
+// Variable width types
+
+typedef SerializableString<Uint8, Uint8> Vbin8;
+typedef SerializableString<char, Uint8, 1> Str8Latin;
+typedef SerializableString<char, Uint8> Str8;
+typedef SerializableString<Uint16, Uint8> Str8Utf16;
+
+typedef SerializableString<Uint8, Uint16> Vbin16;
+typedef SerializableString<char, Uint16, 1> Str16Latin;
+typedef SerializableString<char, Uint16> Str16;
+typedef SerializableString<Uint16, Uint16> Str16Utf16;
+
+typedef SerializableString<Uint8, Uint32> Vbin32;
+
+typedef framing::SequenceSet SequenceSet;
+
+// Forward declare class types.
+class Map;
+class Struct32;
+class UnknownType;
+
+template <class T> struct ArrayDomain;
+typedef ArrayDomain<UnknownType> Array;
+
+// FIXME aconway 2008-04-08: TODO
+struct ByteRanges { template <class S> void serialize(S&) {} };
+struct List { template <class S> void serialize(S&) {} };
+
+// FIXME aconway 2008-03-10: dummy ostream operators
+inline std::ostream& operator<<(std::ostream& o, const ByteRanges&) { return o; }
+inline std::ostream& operator<<(std::ostream& o, const SequenceSet&) { return o; }
+inline std::ostream& operator<<(std::ostream& o, const List&) { return o; }
+
+enum SegmentType { CONTROL, COMMAND, HEADER, BODY };
+
+inline SerializeAs<SegmentType, uint8_t> serializable(SegmentType& st) {
+ return SerializeAs<SegmentType, uint8_t>(st);
+}
+
+
+}} // namespace qpid::amqp_0_10
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/amqp_0_10/complex_types.cpp b/RC9/qpid/cpp/src/qpid/amqp_0_10/complex_types.cpp
new file mode 100644
index 0000000000..656d363ba6
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/amqp_0_10/complex_types.cpp
@@ -0,0 +1,84 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/amqp_0_10/UnknownStruct.h"
+#include "qpid/amqp_0_10/ApplyCommand.h"
+#include "qpid/amqp_0_10/ApplyControl.h"
+#include "qpid/amqp_0_10/ApplyStruct.h"
+#include "qpid/amqp_0_10/apply.h"
+#include <iostream>
+
+namespace qpid {
+namespace amqp_0_10 {
+// Functors for getting static values from a visitable base type.
+
+#define QPID_STATIC_VALUE_GETTER(NAME, TYPE, VALUE) \
+ struct NAME : public ApplyFunctor<TYPE> { \
+ template <class T> TYPE operator()(const T&) const { return T::VALUE; }\
+ }
+
+QPID_STATIC_VALUE_GETTER(GetCode, uint8_t, CODE);
+QPID_STATIC_VALUE_GETTER(GetSize, uint8_t, SIZE);
+QPID_STATIC_VALUE_GETTER(GetPack, uint8_t, PACK);
+QPID_STATIC_VALUE_GETTER(GetClassCode, uint8_t, CLASS_CODE);
+QPID_STATIC_VALUE_GETTER(GetName, const char*, NAME);
+QPID_STATIC_VALUE_GETTER(GetClassName, const char*, CLASS_NAME);
+
+
+uint8_t Command::getCode() const { return apply(GetCode(), *this); }
+uint8_t Command::getClassCode() const { return apply(GetClassCode(), *this); }
+const char* Command::getName() const { return apply(GetName(), *this); }
+const char* Command::getClassName() const { return apply(GetClassName(), *this); }
+
+uint8_t Control::getCode() const { return apply(GetCode(), *this); }
+uint8_t Control::getClassCode() const { return apply(GetClassCode(), *this); }
+const char* Control::getName() const { return apply(GetName(), *this); }
+const char* Control::getClassName() const { return apply(GetClassName(), *this); }
+
+// Special cases for UnknownStruct
+struct GetStructCode : public GetCode {
+ using GetCode::operator();
+ uint8_t operator()(const UnknownStruct& u) const { return u.getCode(); }
+};
+
+struct GetStructClassCode : public GetClassCode {
+ using GetClassCode::operator();
+ uint8_t operator()(const UnknownStruct& u) const { return u.getClassCode(); }
+};
+
+uint8_t Struct::getCode() const { return apply(GetStructCode(), *this); }
+uint8_t Struct::getClassCode() const { return apply(GetStructClassCode(), *this); }
+uint8_t Struct::getPack() const { return apply(GetPack(), *this); }
+uint8_t Struct::getSize() const { return apply(GetSize(), *this); }
+
+struct PrintVisitor {
+ typedef std::ostream& result_type;
+ std::ostream& out;
+ PrintVisitor(std::ostream& o) : out(o) {}
+ template <class T> result_type operator()(const T& t) const { return out << t; }
+};
+
+std::ostream& operator<<(std::ostream& o, const Command& x) { return apply(PrintVisitor(o), x); }
+std::ostream& operator<<(std::ostream& o, const Control& x) { return apply(PrintVisitor(o), x); }
+std::ostream& operator<<(std::ostream& o, const Struct& x) { return apply(PrintVisitor(o), x); }
+
+}} // namespace qpid::amqp_0_10
+
diff --git a/RC9/qpid/cpp/src/qpid/assert.cpp b/RC9/qpid/cpp/src/qpid/assert.cpp
new file mode 100644
index 0000000000..5d039da528
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/assert.cpp
@@ -0,0 +1,45 @@
+#ifndef QPID_ASSERT_CPP
+#define QPID_ASSERT_CPP
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <sstream>
+#include <iostream>
+#include "qpid/framing/reply_exceptions.h"
+#include <stdlib.h>
+
+namespace qpid {
+
+void assert_fail(char const * expr, char const * function, char const * file, long line) {
+ std::ostringstream msg;
+ msg << "Internal error: " << expr << " in function " << function
+ << "(" << file << ":" << line << ")";
+#ifdef NDEBUG
+ throw framing::InternalErrorException(msg.str());
+#else
+ std::cerr << msg << std::endl;
+ abort();
+#endif
+}
+
+} // namespace qpid
+
+#endif /*!QPID_ASSERT_CPP*/
diff --git a/RC9/qpid/cpp/src/qpid/assert.h b/RC9/qpid/cpp/src/qpid/assert.h
new file mode 100644
index 0000000000..49e7c5355d
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/assert.h
@@ -0,0 +1,38 @@
+#ifndef QPID_ASSERT_H
+#define QPID_ASSERT_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <boost/current_function.hpp>
+
+/**
+ * Abort if !expr in debug mode, throw an exception if NDEBUG is set.
+ */
+#define QPID_ASSERT(expr) ((expr) ? static_cast<void>(0) : ::qpid::assert_fail(#expr, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__))
+
+namespace qpid {
+
+void assert_fail(char const * expr, char const * function, char const * file, long line);
+
+} // namespace qpid
+
+#endif /*!QPID_ASSERT_H*/
diff --git a/RC9/qpid/cpp/src/qpid/broker/AclModule.h b/RC9/qpid/cpp/src/qpid/broker/AclModule.h
new file mode 100644
index 0000000000..4bb6ca12b4
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/AclModule.h
@@ -0,0 +1,257 @@
+#ifndef QPID_ACLMODULE_ACL_H
+#define QPID_ACLMODULE_ACL_H
+
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+
+#include "qpid/shared_ptr.h"
+#include "qpid/RefCounted.h"
+#include <map>
+#include <set>
+#include <string>
+
+
+namespace qpid {
+
+namespace acl {
+
+enum ObjectType {OBJ_QUEUE, OBJ_EXCHANGE, OBJ_BROKER, OBJ_LINK,
+ OBJ_METHOD, OBJECTSIZE}; // OBJECTSIZE must be last in list
+enum Action {ACT_CONSUME, ACT_PUBLISH, ACT_CREATE, ACT_ACCESS, ACT_BIND,
+ ACT_UNBIND, ACT_DELETE, ACT_PURGE, ACT_UPDATE,
+ ACTIONSIZE}; // ACTIONSIZE must be last in list
+enum Property {PROP_NAME, PROP_DURABLE, PROP_OWNER, PROP_ROUTINGKEY,
+ PROP_PASSIVE, PROP_AUTODELETE, PROP_EXCLUSIVE, PROP_TYPE,
+ PROP_ALTERNATE, PROP_QUEUENAME, PROP_SCHEMAPACKAGE,
+ PROP_SCHEMACLASS};
+enum AclResult {ALLOW, ALLOWLOG, DENY, DENYLOG};
+
+} // namespace acl
+
+namespace broker {
+
+
+class AclModule
+{
+
+public:
+
+ // effienty turn off ACL on message transfer.
+ virtual bool doTransferAcl()=0;
+
+ virtual bool authorise(const std::string& id, const acl::Action& action, const acl::ObjectType& objType, const std::string& name,
+ std::map<acl::Property, std::string>* params=0)=0;
+ virtual bool authorise(const std::string& id, const acl::Action& action, const acl::ObjectType& objType, const std::string& ExchangeName,
+ const std::string& RoutingKey)=0;
+ // create specilied authorise methods for cases that need faster matching as needed.
+
+ virtual ~AclModule() {};
+};
+
+} // namespace broker
+
+namespace acl {
+
+class AclHelper {
+ private:
+ AclHelper(){}
+ public:
+ static inline ObjectType getObjectType(const std::string& str) {
+ if (str.compare("queue") == 0) return OBJ_QUEUE;
+ if (str.compare("exchange") == 0) return OBJ_EXCHANGE;
+ if (str.compare("broker") == 0) return OBJ_BROKER;
+ if (str.compare("link") == 0) return OBJ_LINK;
+ if (str.compare("method") == 0) return OBJ_METHOD;
+ throw str;
+ }
+ static inline std::string getObjectTypeStr(const ObjectType o) {
+ switch (o) {
+ case OBJ_QUEUE: return "queue";
+ case OBJ_EXCHANGE: return "exchange";
+ case OBJ_BROKER: return "broker";
+ case OBJ_LINK: return "link";
+ case OBJ_METHOD: return "method";
+ default: assert(false); // should never get here
+ }
+ return "";
+ }
+ static inline Action getAction(const std::string& str) {
+ if (str.compare("consume") == 0) return ACT_CONSUME;
+ if (str.compare("publish") == 0) return ACT_PUBLISH;
+ if (str.compare("create") == 0) return ACT_CREATE;
+ if (str.compare("access") == 0) return ACT_ACCESS;
+ if (str.compare("bind") == 0) return ACT_BIND;
+ if (str.compare("unbind") == 0) return ACT_UNBIND;
+ if (str.compare("delete") == 0) return ACT_DELETE;
+ if (str.compare("purge") == 0) return ACT_PURGE;
+ if (str.compare("update") == 0) return ACT_UPDATE;
+ throw str;
+ }
+ static inline std::string getActionStr(const Action a) {
+ switch (a) {
+ case ACT_CONSUME: return "consume";
+ case ACT_PUBLISH: return "publish";
+ case ACT_CREATE: return "create";
+ case ACT_ACCESS: return "access";
+ case ACT_BIND: return "bind";
+ case ACT_UNBIND: return "unbind";
+ case ACT_DELETE: return "delete";
+ case ACT_PURGE: return "purge";
+ case ACT_UPDATE: return "update";
+ default: assert(false); // should never get here
+ }
+ return "";
+ }
+ static inline Property getProperty(const std::string& str) {
+ if (str.compare("name") == 0) return PROP_NAME;
+ if (str.compare("durable") == 0) return PROP_DURABLE;
+ if (str.compare("owner") == 0) return PROP_OWNER;
+ if (str.compare("routingkey") == 0) return PROP_ROUTINGKEY;
+ if (str.compare("passive") == 0) return PROP_PASSIVE;
+ if (str.compare("autodelete") == 0) return PROP_AUTODELETE;
+ if (str.compare("exclusive") == 0) return PROP_EXCLUSIVE;
+ if (str.compare("type") == 0) return PROP_TYPE;
+ if (str.compare("alternate") == 0) return PROP_ALTERNATE;
+ if (str.compare("queuename") == 0) return PROP_QUEUENAME;
+ if (str.compare("schemapackage") == 0) return PROP_SCHEMAPACKAGE;
+ if (str.compare("schemaclass") == 0) return PROP_SCHEMACLASS;
+ throw str;
+ }
+ static inline std::string getPropertyStr(const Property p) {
+ switch (p) {
+ case PROP_NAME: return "name";
+ case PROP_DURABLE: return "durable";
+ case PROP_OWNER: return "owner";
+ case PROP_ROUTINGKEY: return "routingkey";
+ case PROP_PASSIVE: return "passive";
+ case PROP_AUTODELETE: return "autodelete";
+ case PROP_EXCLUSIVE: return "exclusive";
+ case PROP_TYPE: return "type";
+ case PROP_ALTERNATE: return "alternate";
+ case PROP_QUEUENAME: return "queuename";
+ case PROP_SCHEMAPACKAGE: return "schemapackage";
+ case PROP_SCHEMACLASS: return "schemaclass";
+ default: assert(false); // should never get here
+ }
+ return "";
+ }
+ static inline AclResult getAclResult(const std::string& str) {
+ if (str.compare("allow") == 0) return ALLOW;
+ if (str.compare("allow-log") == 0) return ALLOWLOG;
+ if (str.compare("deny") == 0) return DENY;
+ if (str.compare("deny-log") == 0) return DENYLOG;
+ throw str;
+ }
+ static inline std::string getAclResultStr(const AclResult r) {
+ switch (r) {
+ case ALLOW: return "allow";
+ case ALLOWLOG: return "allow-log";
+ case DENY: return "deny";
+ case DENYLOG: return "deny-log";
+ default: assert(false); // should never get here
+ }
+ return "";
+ }
+
+ typedef std::set<Property> propSet;
+ typedef boost::shared_ptr<propSet> propSetPtr;
+ typedef std::pair<Action, propSetPtr> actionPair;
+ typedef std::map<Action, propSetPtr> actionMap;
+ typedef boost::shared_ptr<actionMap> actionMapPtr;
+ typedef std::pair<ObjectType, actionMapPtr> objectPair;
+ typedef std::map<ObjectType, actionMapPtr> objectMap;
+ typedef objectMap::const_iterator omCitr;
+ typedef boost::shared_ptr<objectMap> objectMapPtr;
+
+ // This map contains the legal combinations of object/action/properties found in an ACL file
+ static void loadValidationMap(objectMapPtr& map) {
+ if (!map.get()) return;
+ map->clear();
+ propSetPtr p0; // empty ptr, used for no properties
+
+ // == Exchanges ==
+
+ propSetPtr p1(new propSet);
+ p1->insert(PROP_TYPE);
+ p1->insert(PROP_ALTERNATE);
+ p1->insert(PROP_PASSIVE);
+ p1->insert(PROP_DURABLE);
+
+ propSetPtr p2(new propSet);
+ p2->insert(PROP_ROUTINGKEY);
+
+ propSetPtr p3(new propSet);
+ p3->insert(PROP_QUEUENAME);
+ p3->insert(PROP_ROUTINGKEY);
+
+ actionMapPtr a0(new actionMap);
+ a0->insert(actionPair(ACT_CREATE, p1));
+ a0->insert(actionPair(ACT_DELETE, p0));
+ a0->insert(actionPair(ACT_ACCESS, p0));
+ a0->insert(actionPair(ACT_BIND, p2));
+ a0->insert(actionPair(ACT_UNBIND, p2));
+ a0->insert(actionPair(ACT_ACCESS, p3));
+ a0->insert(actionPair(ACT_PUBLISH, p0));
+
+ map->insert(objectPair(OBJ_EXCHANGE, a0));
+
+ // == Queues ==
+
+ propSetPtr p4(new propSet);
+ p3->insert(PROP_ALTERNATE);
+ p3->insert(PROP_PASSIVE);
+ p3->insert(PROP_DURABLE);
+ p3->insert(PROP_EXCLUSIVE);
+ p3->insert(PROP_AUTODELETE);
+
+ actionMapPtr a1(new actionMap);
+ a1->insert(actionPair(ACT_ACCESS, p0));
+ a1->insert(actionPair(ACT_CREATE, p4));
+ a1->insert(actionPair(ACT_PURGE, p0));
+ a1->insert(actionPair(ACT_DELETE, p0));
+ a1->insert(actionPair(ACT_CONSUME, p0));
+
+ map->insert(objectPair(OBJ_QUEUE, a1));
+
+ // == Links ==
+
+ actionMapPtr a2(new actionMap);
+ a2->insert(actionPair(ACT_CREATE, p0));
+
+ map->insert(objectPair(OBJ_LINK, a2));
+
+ // == Method ==
+
+ propSetPtr p5(new propSet);
+ p5->insert(PROP_SCHEMAPACKAGE);
+ p5->insert(PROP_SCHEMACLASS);
+
+ actionMapPtr a4(new actionMap);
+ a4->insert(actionPair(ACT_ACCESS, p5));
+
+ map->insert(objectPair(OBJ_METHOD, a4));
+ }
+};
+
+
+}} // namespace qpid::acl
+
+#endif // QPID_ACLMODULE_ACL_H
diff --git a/RC9/qpid/cpp/src/qpid/broker/Bridge.cpp b/RC9/qpid/cpp/src/qpid/broker/Bridge.cpp
new file mode 100644
index 0000000000..f9cb7ccd3c
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/Bridge.cpp
@@ -0,0 +1,294 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "Bridge.h"
+#include "ConnectionState.h"
+#include "Connection.h"
+#include "LinkRegistry.h"
+
+#include "qpid/agent/ManagementAgent.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/log/Statement.h"
+#include <iostream>
+
+using qpid::framing::FieldTable;
+using qpid::framing::Uuid;
+using qpid::framing::Buffer;
+using qpid::management::ManagementAgent;
+namespace _qmf = qmf::org::apache::qpid::broker;
+
+namespace
+{
+const std::string qpidFedOp("qpid.fed.op");
+const std::string qpidFedTags("qpid.fed.tags");
+const std::string qpidFedOrigin("qpid.fed.origin");
+
+const std::string fedOpBind("B");
+const std::string fedOpUnbind("U");
+const std::string fedOpReorigin("R");
+const std::string fedOpHello("H");
+}
+
+namespace qpid {
+namespace broker {
+
+void Bridge::PushHandler::handle(framing::AMQFrame& frame)
+{
+ conn->received(frame);
+}
+
+Bridge::Bridge(Link* _link, framing::ChannelId _id, CancellationListener l,
+ const _qmf::ArgsLinkBridge& _args) :
+ link(_link), id(_id), args(_args), mgmtObject(0),
+ listener(l), name(Uuid(true).str()), queueName("bridge_queue_"), persistenceId(0)
+{
+ std::stringstream title;
+ title << id << "_" << link->getBroker()->getFederationTag();
+ queueName += title.str();
+ ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+ if (agent != 0) {
+ mgmtObject = new _qmf::Bridge
+ (agent, this, link, id, args.i_durable, args.i_src, args.i_dest,
+ args.i_key, args.i_srcIsQueue, args.i_srcIsLocal,
+ args.i_tag, args.i_excludes, args.i_dynamic);
+ if (!args.i_durable)
+ agent->addObject(mgmtObject);
+ }
+}
+
+Bridge::~Bridge()
+{
+ mgmtObject->resourceDestroy();
+}
+
+void Bridge::create(ConnectionState& c)
+{
+ connState = &c;
+ if (args.i_srcIsLocal) {
+ if (args.i_dynamic)
+ throw Exception("Dynamic routing not supported for push routes");
+ // Point the bridging commands at the local connection handler
+ Connection* conn = dynamic_cast<Connection*>(&c);
+ if (conn == 0)
+ return;
+ pushHandler.reset(new PushHandler(conn));
+ channelHandler.reset(new framing::ChannelHandler(id, pushHandler.get()));
+ } else {
+ // Point the bridging commands at the remote peer broker
+ channelHandler.reset(new framing::ChannelHandler(id, &(connState->getOutput())));
+ }
+
+ session.reset(new framing::AMQP_ServerProxy::Session(*channelHandler));
+ peer.reset(new framing::AMQP_ServerProxy(*channelHandler));
+
+ session->attach(name, false);
+ session->commandPoint(0,0);
+
+ if (args.i_srcIsQueue) {
+ peer->getMessage().subscribe(args.i_src, args.i_dest, 1, 0, false, "", 0, FieldTable());
+ peer->getMessage().flow(args.i_dest, 0, 0xFFFFFFFF);
+ peer->getMessage().flow(args.i_dest, 1, 0xFFFFFFFF);
+ } else {
+ FieldTable queueSettings;
+
+ if (args.i_tag.size()) {
+ queueSettings.setString("qpid.trace.id", args.i_tag);
+ } else {
+ const string& peerTag = connState->getFederationPeerTag();
+ if (peerTag.size())
+ queueSettings.setString("qpid.trace.id", peerTag);
+ }
+
+ if (args.i_excludes.size()) {
+ queueSettings.setString("qpid.trace.exclude", args.i_excludes);
+ } else {
+ const string& localTag = link->getBroker()->getFederationTag();
+ if (localTag.size())
+ queueSettings.setString("qpid.trace.exclude", localTag);
+ }
+
+ bool durable = false;//should this be an arg, or would be use srcIsQueue for durable queues?
+ bool autoDelete = !durable;//auto delete transient queues?
+ peer->getQueue().declare(queueName, "", false, durable, true, autoDelete, queueSettings);
+ if (!args.i_dynamic)
+ peer->getExchange().bind(queueName, args.i_src, args.i_key, FieldTable());
+ peer->getMessage().subscribe(queueName, args.i_dest, 1, 0, false, "", 0, FieldTable());
+ peer->getMessage().flow(args.i_dest, 0, 0xFFFFFFFF);
+ peer->getMessage().flow(args.i_dest, 1, 0xFFFFFFFF);
+
+ if (args.i_dynamic) {
+ Exchange::shared_ptr exchange = link->getBroker()->getExchanges().get(args.i_src);
+ if (exchange.get() == 0)
+ throw Exception("Exchange not found for dynamic route");
+ exchange->registerDynamicBridge(this);
+ }
+ }
+}
+
+void Bridge::cancel()
+{
+ peer->getMessage().cancel(args.i_dest);
+ peer->getSession().detach(name);
+ if (args.i_dynamic) {
+ Exchange::shared_ptr exchange = link->getBroker()->getExchanges().get(args.i_src);
+ if (exchange.get() != 0)
+ exchange->removeDynamicBridge(this);
+ }
+}
+
+void Bridge::destroy()
+{
+ listener(this);
+}
+
+void Bridge::setPersistenceId(uint64_t id) const
+{
+ if (mgmtObject != 0 && persistenceId == 0) {
+ ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+ agent->addObject (mgmtObject, id);
+ }
+ persistenceId = id;
+}
+
+const string& Bridge::getName() const
+{
+ return name;
+}
+
+Bridge::shared_ptr Bridge::decode(LinkRegistry& links, Buffer& buffer)
+{
+ string host;
+ uint16_t port;
+ string src;
+ string dest;
+ string key;
+ string id;
+ string excludes;
+
+ buffer.getShortString(host);
+ port = buffer.getShort();
+ bool durable(buffer.getOctet());
+ buffer.getShortString(src);
+ buffer.getShortString(dest);
+ buffer.getShortString(key);
+ bool is_queue(buffer.getOctet());
+ bool is_local(buffer.getOctet());
+ buffer.getShortString(id);
+ buffer.getShortString(excludes);
+ bool dynamic(buffer.getOctet());
+
+ return links.declare(host, port, durable, src, dest, key,
+ is_queue, is_local, id, excludes, dynamic).first;
+}
+
+void Bridge::encode(Buffer& buffer) const
+{
+ buffer.putShortString(string("bridge"));
+ buffer.putShortString(link->getHost());
+ buffer.putShort(link->getPort());
+ buffer.putOctet(args.i_durable ? 1 : 0);
+ buffer.putShortString(args.i_src);
+ buffer.putShortString(args.i_dest);
+ buffer.putShortString(args.i_key);
+ buffer.putOctet(args.i_srcIsQueue ? 1 : 0);
+ buffer.putOctet(args.i_srcIsLocal ? 1 : 0);
+ buffer.putShortString(args.i_tag);
+ buffer.putShortString(args.i_excludes);
+ buffer.putOctet(args.i_dynamic ? 1 : 0);
+}
+
+uint32_t Bridge::encodedSize() const
+{
+ return link->getHost().size() + 1 // short-string (host)
+ + 7 // short-string ("bridge")
+ + 2 // port
+ + 1 // durable
+ + args.i_src.size() + 1
+ + args.i_dest.size() + 1
+ + args.i_key.size() + 1
+ + 1 // srcIsQueue
+ + 1 // srcIsLocal
+ + args.i_tag.size() + 1
+ + args.i_excludes.size() + 1
+ + 1; // dynamic
+}
+
+management::ManagementObject* Bridge::GetManagementObject (void) const
+{
+ return (management::ManagementObject*) mgmtObject;
+}
+
+management::Manageable::status_t Bridge::ManagementMethod(uint32_t methodId,
+ management::Args& /*args*/,
+ string&)
+{
+ if (methodId == _qmf::Bridge::METHOD_CLOSE) {
+ //notify that we are closed
+ destroy();
+ return management::Manageable::STATUS_OK;
+ } else {
+ return management::Manageable::STATUS_UNKNOWN_METHOD;
+ }
+}
+
+void Bridge::propagateBinding(const string& key, const string& tagList,
+ const string& op, const string& origin)
+{
+ const string& localTag = link->getBroker()->getFederationTag();
+ const string& peerTag = connState->getFederationPeerTag();
+
+ if (tagList.find(peerTag) == tagList.npos) {
+ FieldTable bindArgs;
+ string newTagList(tagList + string(tagList.empty() ? "" : ",") + localTag);
+
+ bindArgs.setString(qpidFedOp, op);
+ bindArgs.setString(qpidFedTags, newTagList);
+ if (origin.empty())
+ bindArgs.setString(qpidFedOrigin, localTag);
+ else
+ bindArgs.setString(qpidFedOrigin, origin);
+
+ peer->getExchange().bind(queueName, args.i_src, key, bindArgs);
+ }
+}
+
+void Bridge::sendReorigin()
+{
+ FieldTable bindArgs;
+
+ bindArgs.setString(qpidFedOp, fedOpReorigin);
+ bindArgs.setString(qpidFedTags, link->getBroker()->getFederationTag());
+
+ peer->getExchange().bind(queueName, args.i_src, args.i_key, bindArgs);
+}
+
+bool Bridge::containsLocalTag(const string& tagList) const
+{
+ const string& localTag = link->getBroker()->getFederationTag();
+ return (tagList.find(localTag) != tagList.npos);
+}
+
+const string& Bridge::getLocalTag() const
+{
+ return link->getBroker()->getFederationTag();
+}
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/broker/Bridge.h b/RC9/qpid/cpp/src/qpid/broker/Bridge.h
new file mode 100644
index 0000000000..c530a5d696
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/Bridge.h
@@ -0,0 +1,105 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _Bridge_
+#define _Bridge_
+
+#include "PersistableConfig.h"
+#include "qpid/framing/AMQP_ServerProxy.h"
+#include "qpid/framing/ChannelHandler.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/framing/FrameHandler.h"
+#include "qpid/management/Manageable.h"
+#include "Exchange.h"
+#include "qmf/org/apache/qpid/broker/ArgsLinkBridge.h"
+#include "qmf/org/apache/qpid/broker/Bridge.h"
+
+#include <boost/function.hpp>
+#include <memory>
+
+namespace qpid {
+namespace broker {
+
+class Connection;
+class ConnectionState;
+class Link;
+class LinkRegistry;
+
+class Bridge : public PersistableConfig, public management::Manageable, public Exchange::DynamicBridge
+{
+public:
+ typedef boost::shared_ptr<Bridge> shared_ptr;
+ typedef boost::function<void(Bridge*)> CancellationListener;
+
+ Bridge(Link* link, framing::ChannelId id, CancellationListener l,
+ const qmf::org::apache::qpid::broker::ArgsLinkBridge& args);
+ ~Bridge();
+
+ void create(ConnectionState& c);
+ void cancel();
+ void destroy();
+ bool isDurable() { return args.i_durable; }
+
+ management::ManagementObject* GetManagementObject() const;
+ management::Manageable::status_t ManagementMethod(uint32_t methodId,
+ management::Args& args,
+ std::string& text);
+
+ // PersistableConfig:
+ void setPersistenceId(uint64_t id) const;
+ uint64_t getPersistenceId() const { return persistenceId; }
+ uint32_t encodedSize() const;
+ void encode(framing::Buffer& buffer) const;
+ const std::string& getName() const;
+ static Bridge::shared_ptr decode(LinkRegistry& links, framing::Buffer& buffer);
+
+ // Exchange::DynamicBridge methods
+ void propagateBinding(const std::string& key, const std::string& tagList, const std::string& op, const std::string& origin);
+ void sendReorigin();
+ bool containsLocalTag(const std::string& tagList) const;
+ const std::string& getLocalTag() const;
+
+private:
+ struct PushHandler : framing::FrameHandler {
+ PushHandler(Connection* c) { conn = c; }
+ void handle(framing::AMQFrame& frame);
+ Connection* conn;
+ };
+
+ std::auto_ptr<PushHandler> pushHandler;
+ std::auto_ptr<framing::ChannelHandler> channelHandler;
+ std::auto_ptr<framing::AMQP_ServerProxy::Session> session;
+ std::auto_ptr<framing::AMQP_ServerProxy> peer;
+
+ Link* link;
+ framing::ChannelId id;
+ qmf::org::apache::qpid::broker::ArgsLinkBridge args;
+ qmf::org::apache::qpid::broker::Bridge* mgmtObject;
+ CancellationListener listener;
+ std::string name;
+ std::string queueName;
+ mutable uint64_t persistenceId;
+ ConnectionState* connState;
+};
+
+
+}}
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/Broker.cpp b/RC9/qpid/cpp/src/qpid/broker/Broker.cpp
new file mode 100644
index 0000000000..64be104b98
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/Broker.cpp
@@ -0,0 +1,450 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Broker.h"
+#include "DirectExchange.h"
+#include "FanOutExchange.h"
+#include "HeadersExchange.h"
+#include "MessageStoreModule.h"
+#include "NullMessageStore.h"
+#include "RecoveryManagerImpl.h"
+#include "SaslAuthenticator.h"
+#include "TopicExchange.h"
+#include "Link.h"
+
+#include "qmf/org/apache/qpid/broker/Package.h"
+#include "qmf/org/apache/qpid/broker/ArgsBrokerEcho.h"
+#include "qmf/org/apache/qpid/broker/ArgsBrokerQueueMoveMessages.h"
+#include "qpid/management/ManagementExchange.h"
+#include "qpid/log/Statement.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/ProtocolInitiation.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/sys/ProtocolFactory.h"
+#include "qpid/sys/Poller.h"
+#include "qpid/sys/Dispatcher.h"
+#include "qpid/sys/Thread.h"
+#include "qpid/sys/Time.h"
+#include "qpid/sys/ConnectionInputHandler.h"
+#include "qpid/sys/ConnectionInputHandlerFactory.h"
+#include "qpid/sys/TimeoutHandler.h"
+#include "qpid/sys/SystemInfo.h"
+#include "qpid/Address.h"
+#include "qpid/Url.h"
+#include "qpid/Version.h"
+
+#include <boost/bind.hpp>
+
+#include <iostream>
+#include <memory>
+#include <stdlib.h>
+
+using qpid::sys::ProtocolFactory;
+using qpid::sys::Poller;
+using qpid::sys::Dispatcher;
+using qpid::sys::Thread;
+using qpid::framing::FrameHandler;
+using qpid::framing::ChannelId;
+using qpid::management::ManagementBroker;
+using qpid::management::ManagementObject;
+using qpid::management::Manageable;
+using qpid::management::Args;
+namespace _qmf = qmf::org::apache::qpid::broker;
+
+namespace qpid {
+namespace broker {
+
+Broker::Options::Options(const std::string& name) :
+ qpid::Options(name),
+ noDataDir(0),
+ port(DEFAULT_PORT),
+ workerThreads(5),
+ maxConnections(500),
+ connectionBacklog(10),
+ stagingThreshold(5000000),
+ enableMgmt(1),
+ mgmtPubInterval(10),
+ queueCleanInterval(60*10),//10 minutes
+ auth(SaslAuthenticator::available()),
+ realm("QPID"),
+ replayFlushLimit(0),
+ replayHardLimit(0),
+ queueLimit(100*1048576/*100M default limit*/),
+ tcpNoDelay(false),
+ requireEncrypted(false)
+{
+ int c = sys::SystemInfo::concurrency();
+ workerThreads=c+1;
+ char *home = ::getenv("HOME");
+
+ if (home == 0)
+ dataDir += DEFAULT_DATA_DIR_LOCATION;
+ else
+ dataDir += home;
+ dataDir += DEFAULT_DATA_DIR_NAME;
+
+ addOptions()
+ ("data-dir", optValue(dataDir,"DIR"), "Directory to contain persistent data generated by the broker")
+ ("no-data-dir", optValue(noDataDir), "Don't use a data directory. No persistent configuration will be loaded or stored")
+ ("port,p", optValue(port,"PORT"), "Tells the broker to listen on PORT")
+ ("worker-threads", optValue(workerThreads, "N"), "Sets the broker thread pool size")
+ ("max-connections", optValue(maxConnections, "N"), "Sets the maximum allowed connections")
+ ("connection-backlog", optValue(connectionBacklog, "N"), "Sets the connection backlog limit for the server socket")
+ ("staging-threshold", optValue(stagingThreshold, "N"), "Stages messages over N bytes to disk")
+ ("mgmt-enable,m", optValue(enableMgmt,"yes|no"), "Enable Management")
+ ("mgmt-pub-interval", optValue(mgmtPubInterval, "SECONDS"), "Management Publish Interval")
+ ("queue-purge-interval", optValue(queueCleanInterval, "SECONDS"),
+ "Interval between attempts to purge any expired messages from queues")
+ ("auth", optValue(auth, "yes|no"), "Enable authentication, if disabled all incoming connections will be trusted")
+ ("realm", optValue(realm, "REALM"), "Use the given realm when performing authentication")
+ ("default-queue-limit", optValue(queueLimit, "BYTES"), "Default maximum size for queues (in bytes)")
+ ("tcp-nodelay", optValue(tcpNoDelay), "Set TCP_NODELAY on TCP connections")
+ ("require-encryption", optValue(requireEncrypted), "Only accept connections that are encrypted");
+}
+
+const std::string empty;
+const std::string amq_direct("amq.direct");
+const std::string amq_topic("amq.topic");
+const std::string amq_fanout("amq.fanout");
+const std::string amq_match("amq.match");
+const std::string qpid_management("qpid.management");
+
+Broker::Broker(const Broker::Options& conf) :
+ poller(new Poller),
+ config(conf),
+ managementAgentSingleton(!config.enableMgmt),
+ store(0),
+ acl(0),
+ dataDir(conf.noDataDir ? std::string() : conf.dataDir),
+ links(this),
+ factory(new ConnectionFactory(*this)),
+ dtxManager(timer),
+ sessionManager(
+ qpid::SessionState::Configuration(
+ conf.replayFlushLimit*1024, // convert kb to bytes.
+ conf.replayHardLimit*1024),
+ *this),
+ queueCleaner(queues, timer),
+ getKnownBrokers(boost::bind(&Broker::getKnownBrokersImpl, this))
+{
+ if (conf.enableMgmt) {
+ QPID_LOG(info, "Management enabled");
+ managementAgent = managementAgentSingleton.getInstance();
+ ((ManagementBroker*) managementAgent)->configure
+ (dataDir.isEnabled() ? dataDir.getPath() : string(),
+ conf.mgmtPubInterval, this, conf.workerThreads + 3);
+ _qmf::Package packageInitializer(managementAgent);
+
+ System* system = new System (dataDir.isEnabled() ? dataDir.getPath() : string());
+ systemObject = System::shared_ptr(system);
+
+ mgmtObject = new _qmf::Broker(managementAgent, this, system, conf.port);
+ mgmtObject->set_workerThreads(conf.workerThreads);
+ mgmtObject->set_maxConns(conf.maxConnections);
+ mgmtObject->set_connBacklog(conf.connectionBacklog);
+ mgmtObject->set_stagingThreshold(conf.stagingThreshold);
+ mgmtObject->set_mgmtPubInterval(conf.mgmtPubInterval);
+ mgmtObject->set_version(qpid::version);
+ if (dataDir.isEnabled())
+ mgmtObject->set_dataDir(dataDir.getPath());
+ else
+ mgmtObject->clr_dataDir();
+
+ managementAgent->addObject(mgmtObject, 0x1000000000000002LL);
+
+ // Since there is currently no support for virtual hosts, a placeholder object
+ // representing the implied single virtual host is added here to keep the
+ // management schema correct.
+ Vhost* vhost = new Vhost(this);
+ vhostObject = Vhost::shared_ptr(vhost);
+ framing::Uuid uuid(((ManagementBroker*) managementAgent)->getUuid());
+ federationTag = uuid.str();
+ vhostObject->setFederationTag(federationTag);
+
+ queues.setParent(vhost);
+ exchanges.setParent(vhost);
+ links.setParent(vhost);
+ } else {
+ // Management is disabled so there is no broker management ID.
+ // Create a unique uuid to use as the federation tag.
+ framing::Uuid uuid(true);
+ federationTag = uuid.str();
+ }
+
+ QueuePolicy::setDefaultMaxSize(conf.queueLimit);
+
+ // Early-Initialize plugins
+ const Plugin::Plugins& plugins=Plugin::getPlugins();
+ for (Plugin::Plugins::const_iterator i = plugins.begin();
+ i != plugins.end();
+ i++)
+ (*i)->earlyInitialize(*this);
+
+ // If no plugin store module registered itself, set up the null store.
+ if (store.get() == 0)
+ setStore (new NullMessageStore());
+
+ exchanges.declare(empty, DirectExchange::typeName); // Default exchange.
+
+ if (store.get() != 0) {
+ RecoveryManagerImpl recoverer(queues, exchanges, links, dtxManager,
+ conf.stagingThreshold);
+ store->recover(recoverer);
+ }
+
+ //ensure standard exchanges exist (done after recovery from store)
+ declareStandardExchange(amq_direct, DirectExchange::typeName);
+ declareStandardExchange(amq_topic, TopicExchange::typeName);
+ declareStandardExchange(amq_fanout, FanOutExchange::typeName);
+ declareStandardExchange(amq_match, HeadersExchange::typeName);
+
+ if(conf.enableMgmt) {
+ exchanges.declare(qpid_management, ManagementExchange::typeName);
+ Exchange::shared_ptr mExchange = exchanges.get (qpid_management);
+ Exchange::shared_ptr dExchange = exchanges.get (amq_direct);
+ ((ManagementBroker*) managementAgent)->setExchange (mExchange, dExchange);
+ dynamic_pointer_cast<ManagementExchange>(mExchange)->setManagmentAgent
+ ((ManagementBroker*) managementAgent);
+ }
+ else
+ QPID_LOG(info, "Management not enabled");
+
+ /**
+ * SASL setup, can fail and terminate startup
+ */
+ if (conf.auth) {
+ SaslAuthenticator::init(qpid::saslName);
+ QPID_LOG(info, "SASL enabled");
+ }
+
+ // Initialize plugins
+ for (Plugin::Plugins::const_iterator i = plugins.begin();
+ i != plugins.end();
+ i++)
+ (*i)->initialize(*this);
+
+ if (conf.queueCleanInterval) {
+ queueCleaner.start(conf.queueCleanInterval * qpid::sys::TIME_SEC);
+ }
+
+ //initialize known broker urls (TODO: add support for urls for other transports (SSL, RDMA)):
+ boost::shared_ptr<ProtocolFactory> factory = getProtocolFactory(TCP_TRANSPORT);
+ if (factory) {
+ knownBrokers.push_back ( qpid::Url::getIpAddressesUrl ( factory->getPort() ) );
+ }
+}
+
+void Broker::declareStandardExchange(const std::string& name, const std::string& type)
+{
+ bool storeEnabled = store.get() != NULL;
+ std::pair<Exchange::shared_ptr, bool> status = exchanges.declare(name, type, storeEnabled);
+ if (status.second && storeEnabled) {
+ store->create(*status.first, framing::FieldTable ());
+ }
+}
+
+
+boost::intrusive_ptr<Broker> Broker::create(int16_t port)
+{
+ Options config;
+ config.port=port;
+ return create(config);
+}
+
+boost::intrusive_ptr<Broker> Broker::create(const Options& opts)
+{
+ return boost::intrusive_ptr<Broker>(new Broker(opts));
+}
+
+void Broker::setStore (MessageStore* _store)
+{
+ store.reset(new MessageStoreModule (_store));
+ queues.setStore (store.get());
+ dtxManager.setStore (store.get());
+ links.setStore (store.get());
+}
+
+void Broker::run() {
+ accept();
+ QPID_LOG(notice, "Broker running");
+ Dispatcher d(poller);
+ int numIOThreads = config.workerThreads;
+ std::vector<Thread> t(numIOThreads-1);
+
+ // Run n-1 io threads
+ for (int i=0; i<numIOThreads-1; ++i)
+ t[i] = Thread(d);
+
+ // Run final thread
+ d.run();
+
+ // Now wait for n-1 io threads to exit
+ for (int i=0; i<numIOThreads-1; ++i) {
+ t[i].join();
+ }
+}
+
+void Broker::shutdown() {
+ // NB: this function must be async-signal safe, it must not
+ // call any function that is not async-signal safe.
+ // Any unsafe shutdown actions should be done in the destructor.
+ poller->shutdown();
+}
+
+Broker::~Broker() {
+ shutdown();
+ finalize(); // Finalize any plugins.
+ if (config.auth)
+ SaslAuthenticator::fini();
+ QPID_LOG(notice, "Shut down");
+}
+
+ManagementObject* Broker::GetManagementObject(void) const
+{
+ return (ManagementObject*) mgmtObject;
+}
+
+Manageable* Broker::GetVhostObject(void) const
+{
+ return vhostObject.get();
+}
+
+Manageable::status_t Broker::ManagementMethod (uint32_t methodId,
+ Args& args,
+ string&)
+{
+ Manageable::status_t status = Manageable::STATUS_UNKNOWN_METHOD;
+
+ QPID_LOG (debug, "Broker::ManagementMethod [id=" << methodId << "]");
+
+ switch (methodId)
+ {
+ case _qmf::Broker::METHOD_ECHO :
+ status = Manageable::STATUS_OK;
+ break;
+ case _qmf::Broker::METHOD_CONNECT : {
+ _qmf::ArgsBrokerConnect& hp=
+ dynamic_cast<_qmf::ArgsBrokerConnect&>(args);
+
+ string transport = hp.i_transport.empty() ? TCP_TRANSPORT : hp.i_transport;
+ if (!getProtocolFactory(transport)) {
+ QPID_LOG(error, "Transport '" << transport << "' not supported");
+ return Manageable::STATUS_NOT_IMPLEMENTED;
+ }
+ std::pair<Link::shared_ptr, bool> response =
+ links.declare (hp.i_host, hp.i_port, transport, hp.i_durable,
+ hp.i_authMechanism, hp.i_username, hp.i_password);
+ if (hp.i_durable && response.second)
+ store->create(*response.first);
+ status = Manageable::STATUS_OK;
+ break;
+ }
+ case _qmf::Broker::METHOD_QUEUEMOVEMESSAGES : {
+ _qmf::ArgsBrokerQueueMoveMessages& moveArgs=
+ dynamic_cast<_qmf::ArgsBrokerQueueMoveMessages&>(args);
+ if (queueMoveMessages(moveArgs.i_srcQueue, moveArgs.i_destQueue, moveArgs.i_qty))
+ status = Manageable::STATUS_OK;
+ else
+ return Manageable::STATUS_INVALID_PARAMETER;
+ break;
+ }
+ default:
+ status = Manageable::STATUS_NOT_IMPLEMENTED;
+ break;
+ }
+
+ return status;
+}
+
+boost::shared_ptr<ProtocolFactory> Broker::getProtocolFactory(const std::string& name) const {
+ ProtocolFactoryMap::const_iterator i
+ = name.empty() ? protocolFactories.begin() : protocolFactories.find(name);
+ if (i == protocolFactories.end()) return boost::shared_ptr<ProtocolFactory>();
+ else return i->second;
+}
+
+uint16_t Broker::getPort(const std::string& name) const {
+ boost::shared_ptr<ProtocolFactory> factory = getProtocolFactory(name);
+ if (factory) {
+ return factory->getPort();
+ } else {
+ throw NoSuchTransportException(QPID_MSG("No such transport: '" << name << "'"));
+ }
+}
+
+void Broker::registerProtocolFactory(const std::string& name, ProtocolFactory::shared_ptr protocolFactory) {
+ protocolFactories[name] = protocolFactory;
+}
+
+void Broker::accept() {
+ for (ProtocolFactoryMap::const_iterator i = protocolFactories.begin(); i != protocolFactories.end(); i++) {
+ i->second->accept(poller, factory.get());
+ }
+}
+
+void Broker::connect(
+ const std::string& host, uint16_t port, const std::string& transport,
+ boost::function2<void, int, std::string> failed,
+ sys::ConnectionCodec::Factory* f)
+{
+ boost::shared_ptr<ProtocolFactory> pf = getProtocolFactory(transport);
+ if (pf) pf->connect(poller, host, port, f ? f : factory.get(), failed);
+ else throw NoSuchTransportException(QPID_MSG("Unsupported transport type: " << transport));
+}
+
+void Broker::connect(
+ const Url& url,
+ boost::function2<void, int, std::string> failed,
+ sys::ConnectionCodec::Factory* f)
+{
+ url.throwIfEmpty();
+ const TcpAddress* addr=url[0].get<TcpAddress>();
+ connect(addr->host, addr->port, TCP_TRANSPORT, failed, f);
+}
+
+uint32_t Broker::queueMoveMessages(
+ const std::string& srcQueue,
+ const std::string& destQueue,
+ uint32_t qty)
+{
+ Queue::shared_ptr src_queue = queues.find(srcQueue);
+ if (!src_queue)
+ return 0;
+ Queue::shared_ptr dest_queue = queues.find(destQueue);
+ if (!dest_queue)
+ return 0;
+
+ return src_queue->move(dest_queue, qty);
+}
+
+
+boost::shared_ptr<sys::Poller> Broker::getPoller() { return poller; }
+
+std::vector<Url>
+Broker::getKnownBrokersImpl()
+{
+ return knownBrokers;
+}
+
+const std::string Broker::TCP_TRANSPORT("tcp");
+
+}} // namespace qpid::broker
+
diff --git a/RC9/qpid/cpp/src/qpid/broker/Broker.h b/RC9/qpid/cpp/src/qpid/broker/Broker.h
new file mode 100644
index 0000000000..c64bfa8a9f
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/Broker.h
@@ -0,0 +1,229 @@
+#ifndef _Broker_
+#define _Broker_
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "ConnectionFactory.h"
+#include "ConnectionToken.h"
+#include "DirectExchange.h"
+#include "DtxManager.h"
+#include "ExchangeRegistry.h"
+#include "MessageStore.h"
+#include "QueueRegistry.h"
+#include "LinkRegistry.h"
+#include "SessionManager.h"
+#include "QueueCleaner.h"
+#include "Vhost.h"
+#include "System.h"
+#include "Timer.h"
+#include "qpid/management/Manageable.h"
+#include "qpid/management/ManagementBroker.h"
+#include "qmf/org/apache/qpid/broker/Broker.h"
+#include "qmf/org/apache/qpid/broker/ArgsBrokerConnect.h"
+#include "qpid/Options.h"
+#include "qpid/Plugin.h"
+#include "qpid/DataDir.h"
+#include "qpid/framing/FrameHandler.h"
+#include "qpid/framing/OutputHandler.h"
+#include "qpid/framing/ProtocolInitiation.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/RefCounted.h"
+#include "AclModule.h"
+
+#include <boost/intrusive_ptr.hpp>
+#include <string>
+#include <vector>
+
+namespace qpid {
+
+namespace sys {
+ class ProtocolFactory;
+ class Poller;
+}
+
+struct Url;
+
+namespace broker {
+
+static const uint16_t DEFAULT_PORT=5672;
+
+struct NoSuchTransportException : qpid::Exception
+{
+ NoSuchTransportException(const std::string& s) : Exception(s) {}
+ virtual ~NoSuchTransportException() throw() {}
+};
+
+/**
+ * A broker instance.
+ */
+class Broker : public sys::Runnable, public Plugin::Target,
+ public management::Manageable, public RefCounted
+{
+ public:
+
+ struct Options : public qpid::Options {
+ static const std::string DEFAULT_DATA_DIR_LOCATION;
+ static const std::string DEFAULT_DATA_DIR_NAME;
+
+ Options(const std::string& name="Broker Options");
+
+ bool noDataDir;
+ std::string dataDir;
+ uint16_t port;
+ int workerThreads;
+ int maxConnections;
+ int connectionBacklog;
+ uint64_t stagingThreshold;
+ bool enableMgmt;
+ uint16_t mgmtPubInterval;
+ uint16_t queueCleanInterval;
+ bool auth;
+ std::string realm;
+ size_t replayFlushLimit;
+ size_t replayHardLimit;
+ uint queueLimit;
+ bool tcpNoDelay;
+ bool requireEncrypted;
+ };
+
+ private:
+ typedef std::map<std::string, boost::shared_ptr<sys::ProtocolFactory> > ProtocolFactoryMap;
+
+ boost::shared_ptr<sys::Poller> poller;
+ Options config;
+ management::ManagementAgent::Singleton managementAgentSingleton;
+ ProtocolFactoryMap protocolFactories;
+ std::auto_ptr<MessageStore> store;
+ AclModule* acl;
+ DataDir dataDir;
+
+ QueueRegistry queues;
+ ExchangeRegistry exchanges;
+ LinkRegistry links;
+ boost::shared_ptr<sys::ConnectionCodec::Factory> factory;
+ Timer timer;
+ DtxManager dtxManager;
+ SessionManager sessionManager;
+ management::ManagementAgent* managementAgent;
+ qmf::org::apache::qpid::broker::Broker* mgmtObject;
+ Vhost::shared_ptr vhostObject;
+ System::shared_ptr systemObject;
+ QueueCleaner queueCleaner;
+
+ void declareStandardExchange(const std::string& name, const std::string& type);
+
+ std::vector<Url> knownBrokers;
+ std::vector<Url> getKnownBrokersImpl();
+ std::string federationTag;
+
+ public:
+
+
+ virtual ~Broker();
+
+ Broker(const Options& configuration);
+ static boost::intrusive_ptr<Broker> create(const Options& configuration);
+ static boost::intrusive_ptr<Broker> create(int16_t port = DEFAULT_PORT);
+
+ /**
+ * Return listening port. If called before bind this is
+ * the configured port. If called after it is the actual
+ * port, which will be different if the configured port is
+ * 0.
+ */
+ virtual uint16_t getPort(const std::string& name) const;
+
+ /**
+ * Run the broker. Implements Runnable::run() so the broker
+ * can be run in a separate thread.
+ */
+ virtual void run();
+
+ /** Shut down the broker */
+ virtual void shutdown();
+
+ void setStore (MessageStore*);
+ MessageStore& getStore() { return *store; }
+ void setAcl (AclModule* _acl) {acl = _acl;}
+ AclModule* getAcl() { return acl; }
+ QueueRegistry& getQueues() { return queues; }
+ ExchangeRegistry& getExchanges() { return exchanges; }
+ LinkRegistry& getLinks() { return links; }
+ uint64_t getStagingThreshold() { return config.stagingThreshold; }
+ DtxManager& getDtxManager() { return dtxManager; }
+ DataDir& getDataDir() { return dataDir; }
+ Options& getOptions() { return config; }
+
+ SessionManager& getSessionManager() { return sessionManager; }
+ const std::string& getFederationTag() const { return federationTag; }
+
+ management::ManagementObject* GetManagementObject (void) const;
+ management::Manageable* GetVhostObject (void) const;
+ management::Manageable::status_t ManagementMethod (uint32_t methodId,
+ management::Args& args,
+ std::string& text);
+
+ /** Add to the broker's protocolFactorys */
+ void registerProtocolFactory(const std::string& name, boost::shared_ptr<sys::ProtocolFactory>);
+
+ /** Accept connections */
+ void accept();
+
+ /** Create a connection to another broker. */
+ void connect(const std::string& host, uint16_t port,
+ const std::string& transport,
+ boost::function2<void, int, std::string> failed,
+ sys::ConnectionCodec::Factory* =0);
+ /** Create a connection to another broker. */
+ void connect(const Url& url,
+ boost::function2<void, int, std::string> failed,
+ sys::ConnectionCodec::Factory* =0);
+
+ /** Move messages from one queue to another.
+ A zero quantity means to move all messages
+ */
+ uint32_t queueMoveMessages( const std::string& srcQueue,
+ const std::string& destQueue,
+ uint32_t qty);
+
+ // TODO: There isn't a single ProtocolFactory so the use of the following needs to be fixed
+ // For the present just return the first ProtocolFactory registered.
+ boost::shared_ptr<sys::ProtocolFactory> getProtocolFactory(const std::string& name = TCP_TRANSPORT) const;
+
+ /** Expose poller so plugins can register their descriptors. */
+ boost::shared_ptr<sys::Poller> getPoller();
+
+ boost::shared_ptr<sys::ConnectionCodec::Factory> getConnectionFactory() { return factory; }
+ void setConnectionFactory(boost::shared_ptr<sys::ConnectionCodec::Factory> f) { factory = f; }
+
+ Timer& getTimer() { return timer; }
+
+ boost::function<std::vector<Url> ()> getKnownBrokers;
+
+ static const std::string TCP_TRANSPORT;
+};
+
+}}
+
+
+
+#endif /*!_Broker_*/
diff --git a/RC9/qpid/cpp/src/qpid/broker/BrokerSingleton.cpp b/RC9/qpid/cpp/src/qpid/broker/BrokerSingleton.cpp
new file mode 100644
index 0000000000..5ba8c9d1e1
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/BrokerSingleton.cpp
@@ -0,0 +1,36 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "BrokerSingleton.h"
+
+namespace qpid {
+namespace broker {
+
+BrokerSingleton::BrokerSingleton() {
+ if (broker.get() == 0)
+ broker = Broker::create();
+ boost::intrusive_ptr<Broker>::operator=(broker);
+}
+
+BrokerSingleton::~BrokerSingleton() {
+ broker->shutdown();
+}
+
+boost::intrusive_ptr<Broker> BrokerSingleton::broker;
+
+}} // namespace qpid::broker
diff --git a/RC9/qpid/cpp/src/qpid/broker/BrokerSingleton.h b/RC9/qpid/cpp/src/qpid/broker/BrokerSingleton.h
new file mode 100644
index 0000000000..22b707506b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/BrokerSingleton.h
@@ -0,0 +1,52 @@
+#ifndef _broker_BrokerSingleton_h
+#define _broker_BrokerSingleton_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "Broker.h"
+
+namespace qpid {
+namespace broker {
+
+/**
+ * BrokerSingleton is a smart pointer to a process-wide singleton broker
+ * started on an os-chosen port. The broker starts the first time
+ * an instance of BrokerSingleton is created and runs untill the process exits.
+ *
+ * Useful for unit tests that want to share a broker between multiple
+ * tests to reduce overhead of starting/stopping a broker for every test.
+ *
+ * Tests that need a new broker can create it directly.
+ *
+ * THREAD UNSAFE.
+ */
+class BrokerSingleton : public boost::intrusive_ptr<Broker>
+{
+ public:
+ BrokerSingleton();
+ ~BrokerSingleton();
+ private:
+ static boost::intrusive_ptr<Broker> broker;
+};
+
+}} // namespace qpid::broker
+
+
+
+#endif /*!_broker_BrokerSingleton_h*/
diff --git a/RC9/qpid/cpp/src/qpid/broker/Connection.cpp b/RC9/qpid/cpp/src/qpid/broker/Connection.cpp
new file mode 100644
index 0000000000..f0b9980861
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/Connection.cpp
@@ -0,0 +1,271 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "Connection.h"
+#include "SessionState.h"
+#include "Bridge.h"
+
+#include "qpid/log/Statement.h"
+#include "qpid/ptr_map.h"
+#include "qpid/framing/AMQP_ClientProxy.h"
+#include "qpid/framing/enum.h"
+#include "qmf/org/apache/qpid/broker/EventClientConnect.h"
+#include "qmf/org/apache/qpid/broker/EventClientDisconnect.h"
+
+#include <boost/bind.hpp>
+#include <boost/ptr_container/ptr_vector.hpp>
+
+#include <algorithm>
+#include <iostream>
+#include <assert.h>
+
+using namespace qpid::sys;
+using namespace qpid::framing;
+using namespace qpid::sys;
+using qpid::ptr_map_ptr;
+using qpid::management::ManagementAgent;
+using qpid::management::ManagementObject;
+using qpid::management::Manageable;
+using qpid::management::Args;
+namespace _qmf = qmf::org::apache::qpid::broker;
+
+namespace qpid {
+namespace broker {
+
+Connection::Connection(ConnectionOutputHandler* out_, Broker& broker_, const std::string& mgmtId_, bool isLink_) :
+ ConnectionState(out_, broker_),
+ adapter(*this, isLink_),
+ isLink(isLink_),
+ mgmtClosing(false),
+ mgmtId(mgmtId_),
+ mgmtObject(0),
+ links(broker_.getLinks()),
+ agent(0)
+{
+ Manageable* parent = broker.GetVhostObject();
+
+ if (isLink)
+ links.notifyConnection(mgmtId, this);
+
+ if (parent != 0)
+ {
+ agent = ManagementAgent::Singleton::getInstance();
+
+
+ // TODO set last bool true if system connection
+ if (agent != 0)
+ mgmtObject = new _qmf::Connection(agent, this, parent, mgmtId, !isLink, false);
+ agent->addObject(mgmtObject);
+ ConnectionState::setUrl(mgmtId);
+ }
+}
+
+void Connection::requestIOProcessing(boost::function0<void> callback)
+{
+ ioCallback = callback;
+ out.activateOutput();
+}
+
+Connection::~Connection()
+{
+ if (mgmtObject != 0) {
+ mgmtObject->resourceDestroy();
+ if (!isLink)
+ agent->raiseEvent(_qmf::EventClientDisconnect(mgmtId, ConnectionState::getUserId()));
+ }
+ if (isLink)
+ links.notifyClosed(mgmtId);
+}
+
+void Connection::received(framing::AMQFrame& frame) {
+ if (frame.getChannel() == 0 && frame.getMethod()) {
+ adapter.handle(frame);
+ } else {
+ getChannel(frame.getChannel()).in(frame);
+ }
+
+ if (isLink)
+ recordFromServer(frame);
+ else
+ recordFromClient(frame);
+}
+
+void Connection::recordFromServer(framing::AMQFrame& frame)
+{
+ if (mgmtObject != 0)
+ {
+ mgmtObject->inc_framesToClient();
+ mgmtObject->inc_bytesToClient(frame.encodedSize());
+ }
+}
+
+void Connection::recordFromClient(framing::AMQFrame& frame)
+{
+ if (mgmtObject != 0)
+ {
+ mgmtObject->inc_framesFromClient();
+ mgmtObject->inc_bytesFromClient(frame.encodedSize());
+ }
+}
+
+string Connection::getAuthMechanism()
+{
+ if (!isLink)
+ return string("ANONYMOUS");
+
+ return links.getAuthMechanism(mgmtId);
+}
+
+string Connection::getAuthCredentials()
+{
+ if (!isLink)
+ return string();
+
+ if (mgmtObject != 0)
+ {
+ if (links.getAuthMechanism(mgmtId) == "ANONYMOUS")
+ mgmtObject->set_authIdentity("anonymous");
+ else
+ mgmtObject->set_authIdentity(links.getAuthIdentity(mgmtId));
+ }
+
+ return links.getAuthCredentials(mgmtId);
+}
+
+void Connection::notifyConnectionForced(const string& text)
+{
+ if (isLink)
+ links.notifyConnectionForced(mgmtId, text);
+}
+
+void Connection::setUserId(const string& userId)
+{
+ ConnectionState::setUserId(userId);
+ if (mgmtObject != 0) {
+ mgmtObject->set_authIdentity(userId);
+ agent->raiseEvent(_qmf::EventClientConnect(mgmtId, userId));
+ }
+}
+
+void Connection::setFederationLink(bool b)
+{
+ ConnectionState::setFederationLink(b);
+ if (mgmtObject != 0)
+ mgmtObject->set_federationLink(b);
+}
+
+void Connection::close(connection::CloseCode code, const string& text)
+{
+ QPID_LOG_IF(error, code != connection::CLOSE_CODE_NORMAL, "Connection " << mgmtId << " closed by error: " << text << "(" << code << ")");
+ adapter.close(code, text);
+ //make sure we delete dangling pointers from outputTasks before deleting sessions
+ outputTasks.removeAll();
+ channels.clear();
+ getOutput().close();
+}
+
+// Send a close to the client but keep the channels. Used by cluster.
+void Connection::sendClose() {
+ adapter.close(connection::CLOSE_CODE_NORMAL, "OK");
+ getOutput().close();
+}
+
+void Connection::idleOut(){}
+
+void Connection::idleIn(){}
+
+void Connection::closed(){ // Physically closed, suspend open sessions.
+ try {
+ while (!channels.empty())
+ ptr_map_ptr(channels.begin())->handleDetach();
+ while (!exclusiveQueues.empty()) {
+ Queue::shared_ptr q(exclusiveQueues.front());
+ q->releaseExclusiveOwnership();
+ if (q->canAutoDelete()) {
+ Queue::tryAutoDelete(broker, q);
+ }
+ exclusiveQueues.erase(exclusiveQueues.begin());
+ }
+ } catch(std::exception& e) {
+ QPID_LOG(error, QPID_MSG("While closing connection: " << e.what()));
+ assert(0);
+ }
+}
+
+bool Connection::hasOutput() { return outputTasks.hasOutput(); }
+
+bool Connection::doOutput() {
+ try{
+ if (ioCallback)
+ ioCallback(); // Lend the IO thread for management processing
+ ioCallback = 0;
+
+ if (mgmtClosing)
+ close(connection::CLOSE_CODE_CONNECTION_FORCED, "Closed by Management Request");
+ else
+ //then do other output as needed:
+ return outputTasks.doOutput();
+ }catch(ConnectionException& e){
+ close(e.code, e.getMessage());
+ }catch(std::exception& e){
+ close(connection::CLOSE_CODE_CONNECTION_FORCED, e.what());
+ }
+ return false;
+}
+
+void Connection::closeChannel(uint16_t id) {
+ ChannelMap::iterator i = channels.find(id);
+ if (i != channels.end()) channels.erase(i);
+}
+
+SessionHandler& Connection::getChannel(ChannelId id) {
+ ChannelMap::iterator i=channels.find(id);
+ if (i == channels.end()) {
+ i = channels.insert(id, new SessionHandler(*this, id)).first;
+ }
+ return *ptr_map_ptr(i);
+}
+
+ManagementObject* Connection::GetManagementObject(void) const
+{
+ return (ManagementObject*) mgmtObject;
+}
+
+Manageable::status_t Connection::ManagementMethod(uint32_t methodId, Args&, string&)
+{
+ Manageable::status_t status = Manageable::STATUS_UNKNOWN_METHOD;
+
+ QPID_LOG(debug, "Connection::ManagementMethod [id=" << methodId << "]");
+
+ switch (methodId)
+ {
+ case _qmf::Connection::METHOD_CLOSE :
+ mgmtClosing = true;
+ if (mgmtObject != 0) mgmtObject->set_closing(1);
+ out.activateOutput();
+ status = Manageable::STATUS_OK;
+ break;
+ }
+
+ return status;
+}
+
+}}
+
diff --git a/RC9/qpid/cpp/src/qpid/broker/Connection.h b/RC9/qpid/cpp/src/qpid/broker/Connection.h
new file mode 100644
index 0000000000..350ed2c07f
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/Connection.h
@@ -0,0 +1,127 @@
+#ifndef QPID_BROKER_CONNECTION_H
+#define QPID_BROKER_CONNECTION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <memory>
+#include <sstream>
+#include <vector>
+
+#include <boost/ptr_container/ptr_map.hpp>
+
+#include "Broker.h"
+#include "ConnectionHandler.h"
+#include "ConnectionState.h"
+#include "SessionHandler.h"
+#include "qmf/org/apache/qpid/broker/Connection.h"
+#include "qpid/Exception.h"
+#include "qpid/RefCounted.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/AMQP_ClientProxy.h"
+#include "qpid/framing/AMQP_ServerOperations.h"
+#include "qpid/framing/ProtocolVersion.h"
+#include "qpid/agent/ManagementAgent.h"
+#include "qpid/management/Manageable.h"
+#include "qpid/ptr_map.h"
+#include "qpid/sys/AggregateOutput.h"
+#include "qpid/sys/ConnectionInputHandler.h"
+#include "qpid/sys/ConnectionOutputHandler.h"
+#include "qpid/sys/Socket.h"
+#include "qpid/sys/TimeoutHandler.h"
+
+#include <boost/ptr_container/ptr_map.hpp>
+#include <boost/bind.hpp>
+
+#include <algorithm>
+
+namespace qpid {
+namespace broker {
+
+class LinkRegistry;
+
+class Connection : public sys::ConnectionInputHandler,
+ public ConnectionState,
+ public RefCounted
+{
+ public:
+ Connection(sys::ConnectionOutputHandler* out, Broker& broker, const std::string& mgmtId, bool isLink = false);
+ ~Connection ();
+
+ /** Get the SessionHandler for channel. Create if it does not already exist */
+ SessionHandler& getChannel(framing::ChannelId channel);
+
+ /** Close the connection */
+ void close(framing::connection::CloseCode code, const string& text);
+
+ // ConnectionInputHandler methods
+ void received(framing::AMQFrame& frame);
+ void idleOut();
+ void idleIn();
+ bool hasOutput();
+ bool doOutput();
+ void closed();
+
+ void closeChannel(framing::ChannelId channel);
+
+ // Manageable entry points
+ management::ManagementObject* GetManagementObject (void) const;
+ management::Manageable::status_t
+ ManagementMethod (uint32_t methodId, management::Args& args, std::string&);
+
+ void requestIOProcessing (boost::function0<void>);
+ void recordFromServer (framing::AMQFrame& frame);
+ void recordFromClient (framing::AMQFrame& frame);
+ std::string getAuthMechanism();
+ std::string getAuthCredentials();
+ void notifyConnectionForced(const std::string& text);
+ void setUserId(const string& uid);
+ const std::string& getUserId() const { return ConnectionState::getUserId(); }
+ const std::string& getMgmtId() const { return mgmtId; }
+ management::ManagementAgent* getAgent() const { return agent; }
+ void setFederationLink(bool b);
+
+ template <class F> void eachSessionHandler(F f) {
+ for (ChannelMap::iterator i = channels.begin(); i != channels.end(); ++i)
+ f(*ptr_map_ptr(i));
+ }
+
+ void sendClose();
+
+ private:
+ typedef boost::ptr_map<framing::ChannelId, SessionHandler> ChannelMap;
+ typedef std::vector<Queue::shared_ptr>::iterator queue_iterator;
+
+ ChannelMap channels;
+ framing::AMQP_ClientProxy::Connection* client;
+ ConnectionHandler adapter;
+ bool isLink;
+ bool mgmtClosing;
+ const std::string mgmtId;
+ boost::function0<void> ioCallback;
+ qmf::org::apache::qpid::broker::Connection* mgmtObject;
+ LinkRegistry& links;
+ management::ManagementAgent* agent;
+};
+
+}}
+
+#endif /*!QPID_BROKER_CONNECTION_H*/
diff --git a/RC9/qpid/cpp/src/qpid/broker/ConnectionFactory.cpp b/RC9/qpid/cpp/src/qpid/broker/ConnectionFactory.cpp
new file mode 100644
index 0000000000..e6d8c49055
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/ConnectionFactory.cpp
@@ -0,0 +1,56 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "ConnectionFactory.h"
+#include "qpid/framing/ProtocolVersion.h"
+#include "qpid/amqp_0_10/Connection.h"
+#include "qpid/broker/Connection.h"
+
+namespace qpid {
+namespace broker {
+
+using framing::ProtocolVersion;
+typedef std::auto_ptr<amqp_0_10::Connection> ConnectionPtr;
+typedef std::auto_ptr<sys::ConnectionInputHandler> InputPtr;
+
+ConnectionFactory::ConnectionFactory(Broker& b) : broker(b) {}
+
+ConnectionFactory::~ConnectionFactory() {}
+
+sys::ConnectionCodec*
+ConnectionFactory::create(ProtocolVersion v, sys::OutputControl& out, const std::string& id) {
+ if (v == ProtocolVersion(0, 10)) {
+ ConnectionPtr c(new amqp_0_10::Connection(out, id, false));
+ c->setInputHandler(InputPtr(new broker::Connection(c.get(), broker, id, false)));
+ return c.release();
+ }
+ return 0;
+}
+
+sys::ConnectionCodec*
+ConnectionFactory::create(sys::OutputControl& out, const std::string& id) {
+ // used to create connections from one broker to another
+ ConnectionPtr c(new amqp_0_10::Connection(out, id, true));
+ c->setInputHandler(InputPtr(new broker::Connection(c.get(), broker, id, true)));
+ return c.release();
+}
+
+
+}} // namespace qpid::broker
diff --git a/RC9/qpid/cpp/src/qpid/broker/ConnectionFactory.h b/RC9/qpid/cpp/src/qpid/broker/ConnectionFactory.h
new file mode 100644
index 0000000000..c61da81024
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/ConnectionFactory.h
@@ -0,0 +1,50 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _ConnectionFactory_
+#define _ConnectionFactory_
+
+#include "qpid/sys/ConnectionCodec.h"
+
+namespace qpid {
+namespace broker {
+class Broker;
+
+class ConnectionFactory : public sys::ConnectionCodec::Factory
+{
+ public:
+ ConnectionFactory(Broker& b);
+
+ virtual ~ConnectionFactory();
+
+ sys::ConnectionCodec*
+ create(framing::ProtocolVersion, sys::OutputControl&, const std::string& id);
+
+ sys::ConnectionCodec*
+ create(sys::OutputControl&, const std::string& id);
+
+ private:
+ Broker& broker;
+};
+
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/ConnectionHandler.cpp b/RC9/qpid/cpp/src/qpid/broker/ConnectionHandler.cpp
new file mode 100644
index 0000000000..7386ce7229
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/ConnectionHandler.cpp
@@ -0,0 +1,222 @@
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "ConnectionHandler.h"
+#include "Connection.h"
+#include "qpid/framing/ClientInvoker.h"
+#include "qpid/framing/ServerInvoker.h"
+#include "qpid/framing/enum.h"
+#include "qpid/log/Statement.h"
+#include "qpid/Url.h"
+#include "AclModule.h"
+#include "qmf/org/apache/qpid/broker/EventClientConnectFail.h"
+
+using namespace qpid;
+using namespace qpid::broker;
+using namespace qpid::framing;
+namespace _qmf = qmf::org::apache::qpid::broker;
+
+namespace
+{
+const std::string ANONYMOUS = "ANONYMOUS";
+const std::string PLAIN = "PLAIN";
+const std::string en_US = "en_US";
+const std::string QPID_FED_LINK = "qpid.fed_link";
+const std::string QPID_FED_TAG = "qpid.federation_tag";
+}
+
+void ConnectionHandler::close(connection::CloseCode code, const string& text)
+{
+ handler->client.close(code, text);
+}
+
+void ConnectionHandler::handle(framing::AMQFrame& frame)
+{
+ AMQMethodBody* method=frame.getBody()->getMethod();
+ try{
+ bool handled = false;
+ if (handler->serverMode) {
+ handled = invoke(static_cast<AMQP_ServerOperations::ConnectionHandler&>(*handler.get()), *method);
+ } else {
+ handled = invoke(static_cast<AMQP_ClientOperations::ConnectionHandler&>(*handler.get()), *method);
+ }
+ if (!handled) {
+ handler->connection.getChannel(frame.getChannel()).in(frame);
+ }
+
+ }catch(ConnectionException& e){
+ handler->client.close(e.code, e.what());
+ }catch(std::exception& e){
+ handler->client.close(541/*internal error*/, e.what());
+ }
+}
+
+ConnectionHandler::ConnectionHandler(Connection& connection, bool isClient) : handler(new Handler(connection, isClient)) {}
+
+ConnectionHandler::Handler::Handler(Connection& c, bool isClient) :
+ client(c.getOutput()), server(c.getOutput()),
+ connection(c), serverMode(!isClient), acl(0)
+{
+ if (serverMode) {
+
+ acl = connection.getBroker().getAcl();
+
+ FieldTable properties;
+ Array mechanisms(0x95);
+
+ properties.setString(QPID_FED_TAG, connection.getBroker().getFederationTag());
+
+ authenticator = SaslAuthenticator::createAuthenticator(c);
+ authenticator->getMechanisms(mechanisms);
+
+ Array locales(0x95);
+ boost::shared_ptr<FieldValue> l(new Str16Value(en_US));
+ locales.add(l);
+ client.start(properties, mechanisms, locales);
+ }
+}
+
+
+ConnectionHandler::Handler::~Handler() {}
+
+
+void ConnectionHandler::Handler::startOk(const framing::FieldTable& clientProperties,
+ const string& mechanism,
+ const string& response,
+ const string& /*locale*/)
+{
+ try {
+ authenticator->start(mechanism, response);
+ } catch (std::exception& /*e*/) {
+ management::ManagementAgent* agent = connection.getAgent();
+ if (agent) {
+ string error;
+ string uid;
+ authenticator->getError(error);
+ authenticator->getUid(uid);
+ agent->raiseEvent(_qmf::EventClientConnectFail(connection.getMgmtId(), uid, error));
+ }
+ throw;
+ }
+ connection.setFederationLink(clientProperties.get(QPID_FED_LINK));
+ connection.setFederationPeerTag(clientProperties.getAsString(QPID_FED_TAG));
+ if (connection.isFederationLink()) {
+ if (acl && !acl->authorise(connection.getUserId(),acl::ACT_CREATE,acl::OBJ_LINK,"")){
+ client.close(framing::connection::CLOSE_CODE_CONNECTION_FORCED,"ACL denied creating a federation link");
+ return;
+ }
+ QPID_LOG(info, "Connection is a federation link");
+ }
+}
+
+void ConnectionHandler::Handler::secureOk(const string& response)
+{
+ try {
+ authenticator->step(response);
+ } catch (std::exception& /*e*/) {
+ management::ManagementAgent* agent = connection.getAgent();
+ if (agent) {
+ string error;
+ string uid;
+ authenticator->getError(error);
+ authenticator->getUid(uid);
+ agent->raiseEvent(_qmf::EventClientConnectFail(connection.getMgmtId(), uid, error));
+ }
+ throw;
+ }
+}
+
+void ConnectionHandler::Handler::tuneOk(uint16_t /*channelmax*/,
+ uint16_t framemax, uint16_t heartbeat)
+{
+ connection.setFrameMax(framemax);
+ connection.setHeartbeat(heartbeat);
+}
+
+void ConnectionHandler::Handler::open(const string& /*virtualHost*/,
+ const framing::Array& /*capabilities*/, bool /*insist*/)
+{
+ std::vector<Url> urls = connection.broker.getKnownBrokers();
+ framing::Array array(0x95); // str16 array
+ for (std::vector<Url>::iterator i = urls.begin(); i < urls.end(); ++i)
+ array.add(boost::shared_ptr<Str16Value>(new Str16Value(i->str())));
+ client.openOk(array);
+}
+
+
+void ConnectionHandler::Handler::close(uint16_t replyCode, const string& replyText)
+{
+ if (replyCode != 200) {
+ QPID_LOG(warning, "Client closed connection with " << replyCode << ": " << replyText);
+ }
+
+ if (replyCode == framing::connection::CLOSE_CODE_CONNECTION_FORCED)
+ connection.notifyConnectionForced(replyText);
+
+ client.closeOk();
+ connection.getOutput().close();
+}
+
+void ConnectionHandler::Handler::closeOk(){
+ connection.getOutput().close();
+}
+
+
+void ConnectionHandler::Handler::start(const FieldTable& serverProperties,
+ const framing::Array& /*mechanisms*/,
+ const framing::Array& /*locales*/)
+{
+ string mechanism = connection.getAuthMechanism();
+ string response = connection.getAuthCredentials();
+
+ connection.setFederationPeerTag(serverProperties.getAsString(QPID_FED_TAG));
+
+ FieldTable ft;
+ ft.setInt(QPID_FED_LINK,1);
+ ft.setString(QPID_FED_TAG, connection.getBroker().getFederationTag());
+ server.startOk(ft, mechanism, response, en_US);
+}
+
+void ConnectionHandler::Handler::secure(const string& /*challenge*/)
+{
+ server.secureOk("");
+}
+
+void ConnectionHandler::Handler::tune(uint16_t channelMax,
+ uint16_t frameMax,
+ uint16_t /*heartbeatMin*/,
+ uint16_t heartbeatMax)
+{
+ connection.setFrameMax(frameMax);
+ connection.setHeartbeat(heartbeatMax);
+ server.tuneOk(channelMax, frameMax, heartbeatMax);
+ server.open("/", Array(), true);
+}
+
+void ConnectionHandler::Handler::openOk(const framing::Array& /*knownHosts*/)
+{
+}
+
+void ConnectionHandler::Handler::redirect(const string& /*host*/, const framing::Array& /*knownHosts*/)
+{
+
+}
diff --git a/RC9/qpid/cpp/src/qpid/broker/ConnectionHandler.h b/RC9/qpid/cpp/src/qpid/broker/ConnectionHandler.h
new file mode 100644
index 0000000000..d3d5965dfc
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/ConnectionHandler.h
@@ -0,0 +1,95 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _ConnectionAdapter_
+#define _ConnectionAdapter_
+
+#include <memory>
+#include "SaslAuthenticator.h"
+#include "qpid/framing/amqp_types.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/AMQP_ClientOperations.h"
+#include "qpid/framing/AMQP_ClientProxy.h"
+#include "qpid/framing/AMQP_ServerOperations.h"
+#include "qpid/framing/AMQP_ServerProxy.h"
+#include "qpid/framing/enum.h"
+#include "qpid/framing/FrameHandler.h"
+#include "qpid/framing/ProtocolInitiation.h"
+#include "qpid/framing/ProtocolVersion.h"
+#include "qpid/Exception.h"
+#include "AclModule.h"
+
+namespace qpid {
+namespace broker {
+
+class Connection;
+
+class ConnectionHandler : public framing::FrameHandler
+{
+ struct Handler : public framing::AMQP_ServerOperations::ConnectionHandler,
+ public framing::AMQP_ClientOperations::ConnectionHandler
+ {
+ framing::AMQP_ClientProxy::Connection client;
+ framing::AMQP_ServerProxy::Connection server;
+ Connection& connection;
+ bool serverMode;
+ std::auto_ptr<SaslAuthenticator> authenticator;
+ AclModule* acl;
+
+ Handler(Connection& connection, bool isClient);
+ ~Handler();
+ void startOk(const qpid::framing::FieldTable& clientProperties,
+ const std::string& mechanism, const std::string& response,
+ const std::string& locale);
+ void secureOk(const std::string& response);
+ void tuneOk(uint16_t channelMax, uint16_t frameMax, uint16_t heartbeat);
+ void heartbeat() {}
+ void open(const std::string& virtualHost,
+ const framing::Array& capabilities, bool insist);
+ void close(uint16_t replyCode, const std::string& replyText);
+ void closeOk();
+
+
+ void start(const qpid::framing::FieldTable& serverProperties,
+ const framing::Array& mechanisms,
+ const framing::Array& locales);
+
+ void secure(const std::string& challenge);
+
+ void tune(uint16_t channelMax,
+ uint16_t frameMax,
+ uint16_t heartbeatMin,
+ uint16_t heartbeatMax);
+
+ void openOk(const framing::Array& knownHosts);
+
+ void redirect(const std::string& host, const framing::Array& knownHosts);
+ };
+ std::auto_ptr<Handler> handler;
+ public:
+ ConnectionHandler(Connection& connection, bool isClient);
+ void close(framing::connection::CloseCode code, const std::string& text);
+ void handle(framing::AMQFrame& frame);
+};
+
+
+}}
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/ConnectionState.h b/RC9/qpid/cpp/src/qpid/broker/ConnectionState.h
new file mode 100644
index 0000000000..fd69157dbd
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/ConnectionState.h
@@ -0,0 +1,100 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _ConnectionState_
+#define _ConnectionState_
+
+#include <vector>
+
+#include "qpid/sys/AggregateOutput.h"
+#include "qpid/sys/ConnectionOutputHandlerPtr.h"
+#include "qpid/framing/ProtocolVersion.h"
+#include "qpid/management/Manageable.h"
+#include "Broker.h"
+
+namespace qpid {
+namespace broker {
+
+class ConnectionState : public ConnectionToken, public management::Manageable
+{
+ protected:
+ sys::ConnectionOutputHandlerPtr out;
+
+ public:
+ ConnectionState(qpid::sys::ConnectionOutputHandler* o, Broker& b) :
+ out(o),
+ broker(b),
+ outputTasks(out),
+ framemax(65535),
+ heartbeat(0),
+ stagingThreshold(broker.getStagingThreshold()),
+ federationLink(true)
+ {}
+
+
+
+ virtual ~ConnectionState () {}
+
+ uint32_t getFrameMax() const { return framemax; }
+ uint16_t getHeartbeat() const { return heartbeat; }
+ uint64_t getStagingThreshold() const { return stagingThreshold; }
+
+ void setFrameMax(uint32_t fm) { framemax = fm; }
+ void setHeartbeat(uint16_t hb) { heartbeat = hb; }
+ void setStagingThreshold(uint64_t st) { stagingThreshold = st; }
+
+ virtual void setUserId(const string& uid) { userId = uid; }
+ const string& getUserId() const { return userId; }
+
+ void setUrl(const string& _url) { url = _url; }
+ const string& getUrl() const { return url; }
+
+ void setFederationLink(bool b) { federationLink = b; }
+ bool isFederationLink() const { return federationLink; }
+ void setFederationPeerTag(const string& tag) { federationPeerTag = string(tag); }
+ const string& getFederationPeerTag() const { return federationPeerTag; }
+
+ Broker& getBroker() { return broker; }
+
+ Broker& broker;
+ std::vector<Queue::shared_ptr> exclusiveQueues;
+
+ //contained output tasks
+ sys::AggregateOutput outputTasks;
+
+ sys::ConnectionOutputHandlerPtr& getOutput() { return out; }
+ framing::ProtocolVersion getVersion() const { return version; }
+
+ void setOutputHandler(qpid::sys::ConnectionOutputHandler* o) { out.set(o); }
+
+ protected:
+ framing::ProtocolVersion version;
+ uint32_t framemax;
+ uint16_t heartbeat;
+ uint64_t stagingThreshold;
+ string userId;
+ string url;
+ bool federationLink;
+ string federationPeerTag;
+};
+
+}}
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/ConnectionToken.h b/RC9/qpid/cpp/src/qpid/broker/ConnectionToken.h
new file mode 100644
index 0000000000..0e3b301897
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/ConnectionToken.h
@@ -0,0 +1,40 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _ConnectionToken_
+#define _ConnectionToken_
+
+#include "OwnershipToken.h"
+namespace qpid {
+ namespace broker {
+ /**
+ * An empty interface allowing opaque implementations of some
+ * form of token to identify a connection.
+ */
+ class ConnectionToken : public OwnershipToken {
+ public:
+ virtual bool isLocal(const ConnectionToken* t) const { return this == t; }
+ virtual ~ConnectionToken(){}
+ };
+ }
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/Consumer.h b/RC9/qpid/cpp/src/qpid/broker/Consumer.h
new file mode 100644
index 0000000000..5de00668b3
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/Consumer.h
@@ -0,0 +1,53 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _Consumer_
+#define _Consumer_
+
+#include "Message.h"
+#include "QueuedMessage.h"
+#include "OwnershipToken.h"
+
+namespace qpid {
+namespace broker {
+
+class Queue;
+
+class Consumer {
+ const bool acquires;
+ public:
+ typedef boost::shared_ptr<Consumer> shared_ptr;
+
+ framing::SequenceNumber position;
+
+ Consumer(bool preAcquires = true) : acquires(preAcquires) {}
+ bool preAcquires() const { return acquires; }
+ virtual bool deliver(QueuedMessage& msg) = 0;
+ virtual void notify() = 0;
+ virtual bool filter(boost::intrusive_ptr<Message>) { return true; }
+ virtual bool accept(boost::intrusive_ptr<Message>) { return true; }
+ virtual OwnershipToken* getSession() = 0;
+ virtual ~Consumer(){}
+};
+
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/Daemon.cpp b/RC9/qpid/cpp/src/qpid/broker/Daemon.cpp
new file mode 100644
index 0000000000..88eb8fc1cd
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/Daemon.cpp
@@ -0,0 +1,212 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "Daemon.h"
+#include "qpid/log/Statement.h"
+#include "qpid/Exception.h"
+#include "qpid/sys/LockFile.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace qpid {
+namespace broker {
+
+using namespace std;
+using qpid::sys::LockFile;
+
+Daemon::Daemon(std::string _pidDir) : pidDir(_pidDir) {
+ struct stat s;
+ pid = -1;
+ pipeFds[0] = pipeFds[1] = -1;
+
+ if (::stat(pidDir.c_str(), &s)) {
+ if (errno == ENOENT) {
+ if (::mkdir(pidDir.c_str(), 0755))
+ throw Exception ("Can't create PID directory: " + pidDir);
+ }
+ else
+ throw Exception ("PID directory not found: " + pidDir);
+ }
+}
+
+string Daemon::pidFile(string pidDir, uint16_t port) {
+ ostringstream path;
+ path << pidDir << "/qpidd." << port << ".pid";
+ return path.str();
+}
+
+/*
+ * Rewritten using low-level IO, for compatibility
+ * with earlier Boost versions, i.e. 103200.
+ */
+void Daemon::fork()
+{
+ if(::pipe(pipeFds) < 0) throw ErrnoException("Can't create pipe");
+ if ((pid = ::fork()) < 0) throw ErrnoException("Daemon fork failed");
+ if (pid == 0) { // Child
+ try {
+ QPID_LOG(debug, "Forked daemon child process");
+
+ // File descriptors
+ if(::close(pipeFds[0])<0) throw ErrnoException("Cannot close read pipe");
+ if(::close(0)<0) throw ErrnoException("Cannot close stdin");
+ if(::close(1)<0) throw ErrnoException("Cannot close stdout");
+ if(::close(2)<0) throw ErrnoException("Cannot close stderr");
+ int fd=::open("/dev/null",O_RDWR); // stdin
+ if(fd != 0) throw ErrnoException("Cannot re-open stdin");
+ if(::dup(fd)<0) throw ErrnoException("Cannot re-open stdout");
+ if(::dup(fd)<0) throw ErrnoException("Cannot re-open stderror");
+
+ // Misc
+ if(setsid()<0) throw ErrnoException("Cannot set session ID");
+ if(chdir(pidDir.c_str()) < 0) throw ErrnoException("Cannot change directory to "+pidDir);
+ umask(027);
+
+ // Child behavior
+ child();
+ }
+ catch (const exception& e) {
+ QPID_LOG(critical, "Daemon startup failed: " << e.what());
+ uint16_t port = 0;
+ write(pipeFds[1], &port, sizeof(uint16_t));
+
+ std::string pipeFailureMessage = e.what();
+ write ( pipeFds[1],
+ pipeFailureMessage.c_str(),
+ strlen(pipeFailureMessage.c_str())
+ );
+ }
+ }
+ else { // Parent
+ close(pipeFds[1]); // Write side.
+ parent();
+ }
+}
+
+Daemon::~Daemon() {
+ if (!lockFile.empty())
+ unlink(lockFile.c_str());
+}
+
+uint16_t Daemon::wait(int timeout) { // parent waits for child.
+ try {
+ errno = 0;
+ struct timeval tv;
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ /*
+ * Rewritten using low-level IO, for compatibility
+ * with earlier Boost versions, i.e. 103200.
+ */
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(pipeFds[0], &fds);
+ int n=select(FD_SETSIZE, &fds, 0, 0, &tv);
+ if(n==0) throw Exception("Timed out waiting for daemon");
+ if(n<0) throw ErrnoException("Error waiting for daemon");
+ uint16_t port = 0;
+ /*
+ * Read the child's port number from the pipe.
+ */
+ int desired_read = sizeof(uint16_t);
+ if ( desired_read > ::read(pipeFds[0], & port, desired_read) )
+ throw Exception("Cannot read from child process.");
+
+ /*
+ * If the port number is 0, the child has put an error message
+ * on the pipe. Get it and throw it.
+ */
+ if ( 0 == port ) {
+ // Skip whitespace
+ char c = ' ';
+ while ( isspace(c) ) {
+ if ( 1 > ::read(pipeFds[0], &c, 1) )
+ throw Exception("Child port == 0, and no error message on pipe.");
+ }
+
+ // Get Message
+ string errmsg;
+ do {
+ errmsg += c;
+ } while (::read(pipeFds[0], &c, 1));
+ throw Exception("Daemon startup failed"+
+ (errmsg.empty() ? string(".") : ": " + errmsg));
+ }
+ return port;
+ }
+ catch (const std::exception& e) {
+ // Print directly to cerr. The caller will catch and log the
+ // exception, but in the case of a daemon parent process we
+ // also need to be sure the error goes to stderr. A
+ // dameon's logging configuration normally does not log to
+ // stderr.
+ std::cerr << e.what() << endl;
+ throw;
+ }
+}
+
+
+/*
+ * When the child is ready, it writes its pid to the
+ * lockfile and its port number on the pipe back to
+ * its parent process. This indicates that the
+ * child has successfully daemonized. When the parent
+ * hears the good news, it ill exit.
+ */
+void Daemon::ready(uint16_t port) { // child
+ lockFile = pidFile(pidDir, port);
+ LockFile lf(lockFile, true);
+
+ /*
+ * Write the PID to the lockfile.
+ */
+ lf.writePid();
+
+ /*
+ * Write the port number to the parent.
+ */
+ int desired_write = sizeof(uint16_t);
+ if ( desired_write > ::write(pipeFds[1], & port, desired_write) ) {
+ throw Exception("Error writing to parent." );
+ }
+
+ QPID_LOG(debug, "Daemon ready on port: " << port);
+}
+
+/*
+ * The parent process reads the child's pid
+ * from the lockfile.
+ */
+pid_t Daemon::getPid(string _pidDir, uint16_t port) {
+ string name = pidFile(_pidDir, port);
+ LockFile lf(name, false);
+ pid_t pid = lf.readPid();
+ if (kill(pid, 0) < 0 && errno != EPERM) {
+ unlink(name.c_str());
+ throw Exception("Removing stale lock file "+name);
+ }
+ return pid;
+}
+
+
+}} // namespace qpid::broker
diff --git a/RC9/qpid/cpp/src/qpid/broker/Daemon.h b/RC9/qpid/cpp/src/qpid/broker/Daemon.h
new file mode 100644
index 0000000000..98468debb7
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/Daemon.h
@@ -0,0 +1,82 @@
+#ifndef _broker_Daemon_h
+#define _broker_Daemon_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <string>
+#include <boost/scoped_ptr.hpp>
+#include <boost/function.hpp>
+#include <boost/noncopyable.hpp>
+
+namespace qpid {
+namespace broker {
+
+/**
+ * Tools for forking and managing a daemon process.
+ * NB: Only one Daemon instance is allowed in a process.
+ */
+class Daemon : private boost::noncopyable
+{
+ public:
+ /** Check daemon is running on port, throw exception if not */
+ static pid_t getPid(std::string pidDir, uint16_t port);
+
+ Daemon(std::string pidDir);
+
+ virtual ~Daemon();
+
+ /**
+ * Fork a daemon process.
+ * Call parent() in the parent process, child() in the child.
+ */
+ void fork();
+
+ protected:
+
+ /** Called in parent process */
+ virtual void parent() = 0;
+
+ /** Called in child process */
+ virtual void child() = 0;
+
+ /** Call from parent(): wait for child to indicate it is ready.
+ * @timeout in seconds to wait for response.
+ * @return port passed by child to ready().
+ */
+ uint16_t wait(int timeout);
+
+ /** Call from child(): Notify the parent we are ready and write the
+ * PID file.
+ *@param port returned by parent call to wait().
+ */
+ void ready(uint16_t port);
+
+ private:
+ static std::string pidFile(std::string pidDir, uint16_t port);
+
+ pid_t pid;
+ int pipeFds[2];
+ int lockFileFd;
+ std::string lockFile;
+ std::string pidDir;
+};
+
+}} // namespace qpid::broker
+
+#endif /*!_broker_Daemon_h*/
diff --git a/RC9/qpid/cpp/src/qpid/broker/Deliverable.h b/RC9/qpid/cpp/src/qpid/broker/Deliverable.h
new file mode 100644
index 0000000000..e0ceeb2408
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/Deliverable.h
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _Deliverable_
+#define _Deliverable_
+
+#include "Queue.h"
+#include "Message.h"
+
+namespace qpid {
+ namespace broker {
+ class Deliverable{
+ public:
+ bool delivered;
+ Deliverable() : delivered(false) {}
+
+ virtual Message& getMessage() = 0;
+
+ virtual void deliverTo(const boost::shared_ptr<Queue>& queue) = 0;
+ virtual uint64_t contentSize() { return 0; }
+ virtual ~Deliverable(){}
+ };
+ }
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/DeliverableMessage.cpp b/RC9/qpid/cpp/src/qpid/broker/DeliverableMessage.cpp
new file mode 100644
index 0000000000..5fff54b329
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/DeliverableMessage.cpp
@@ -0,0 +1,43 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "DeliverableMessage.h"
+
+using namespace qpid::broker;
+
+DeliverableMessage::DeliverableMessage(const boost::intrusive_ptr<Message>& _msg) : msg(_msg)
+{
+}
+
+void DeliverableMessage::deliverTo(const boost::shared_ptr<Queue>& queue)
+{
+ queue->deliver(msg);
+ delivered = true;
+}
+
+Message& DeliverableMessage::getMessage()
+{
+ return *msg;
+}
+
+uint64_t DeliverableMessage::contentSize ()
+{
+ return msg->contentSize ();
+}
diff --git a/RC9/qpid/cpp/src/qpid/broker/DeliverableMessage.h b/RC9/qpid/cpp/src/qpid/broker/DeliverableMessage.h
new file mode 100644
index 0000000000..f5db473c22
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/DeliverableMessage.h
@@ -0,0 +1,45 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _DeliverableMessage_
+#define _DeliverableMessage_
+
+#include "Deliverable.h"
+#include "Queue.h"
+#include "Message.h"
+
+#include <boost/intrusive_ptr.hpp>
+
+namespace qpid {
+ namespace broker {
+ class DeliverableMessage : public Deliverable{
+ boost::intrusive_ptr<Message> msg;
+ public:
+ DeliverableMessage(const boost::intrusive_ptr<Message>& msg);
+ virtual void deliverTo(const boost::shared_ptr<Queue>& queue);
+ Message& getMessage();
+ uint64_t contentSize();
+ virtual ~DeliverableMessage(){}
+ };
+ }
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/DeliveryAdapter.h b/RC9/qpid/cpp/src/qpid/broker/DeliveryAdapter.h
new file mode 100644
index 0000000000..0e9d7d3929
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/DeliveryAdapter.h
@@ -0,0 +1,53 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _DeliveryAdapter_
+#define _DeliveryAdapter_
+
+#include "DeliveryId.h"
+#include "Message.h"
+#include "qpid/framing/amqp_types.h"
+
+namespace qpid {
+namespace broker {
+
+class DeliveryRecord;
+
+/**
+ * The intention behind this interface is to separate the generic
+ * handling of some form of message delivery to clients that is
+ * contained in the version independent Channel class from the
+ * details required for a particular situation or
+ * version. i.e. where the existing adapters allow (through
+ * supporting the generated interface for a version of the
+ * protocol) inputs of a channel to be adapted to the version
+ * independent part, this does the same for the outputs.
+ */
+class DeliveryAdapter
+{
+ public:
+ virtual void deliver(DeliveryRecord&) = 0;
+ virtual ~DeliveryAdapter(){}
+};
+
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/DeliveryId.h b/RC9/qpid/cpp/src/qpid/broker/DeliveryId.h
new file mode 100644
index 0000000000..05b19f032e
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/DeliveryId.h
@@ -0,0 +1,35 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _DeliveryId_
+#define _DeliveryId_
+
+#include "qpid/framing/SequenceNumber.h"
+#include "qpid/framing/SequenceNumberSet.h"
+
+namespace qpid {
+namespace broker {
+
+ typedef framing::SequenceNumber DeliveryId;
+ typedef framing::SequenceNumberSet DeliveryIds;
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/DeliveryRecord.cpp b/RC9/qpid/cpp/src/qpid/broker/DeliveryRecord.cpp
new file mode 100644
index 0000000000..b0c060aea5
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/DeliveryRecord.cpp
@@ -0,0 +1,214 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "DeliveryRecord.h"
+#include "DeliverableMessage.h"
+#include "SemanticState.h"
+#include "Exchange.h"
+#include "qpid/log/Statement.h"
+#include "qpid/framing/FrameHandler.h"
+#include "qpid/framing/MessageTransferBody.h"
+
+using namespace qpid;
+using namespace qpid::broker;
+using std::string;
+
+DeliveryRecord::DeliveryRecord(const QueuedMessage& _msg,
+ const Queue::shared_ptr& _queue,
+ const std::string& _tag,
+ bool _acquired,
+ bool accepted,
+ bool _windowing,
+ uint32_t _credit) : msg(_msg),
+ queue(_queue),
+ tag(_tag),
+ acquired(_acquired),
+ acceptExpected(!accepted),
+ cancelled(false),
+ completed(false),
+ ended(accepted),
+ windowing(_windowing),
+ credit(msg.payload ? msg.payload->getRequiredCredit() : _credit)
+{}
+
+void DeliveryRecord::setEnded()
+{
+ ended = true;
+ //reset msg pointer, don't need to hold on to it anymore
+ msg.payload = boost::intrusive_ptr<Message>();
+
+ QPID_LOG(debug, "DeliveryRecord::setEnded() id=" << id);
+}
+
+bool DeliveryRecord::matches(DeliveryId tag) const{
+ return id == tag;
+}
+
+bool DeliveryRecord::matchOrAfter(DeliveryId tag) const{
+ return matches(tag) || after(tag);
+}
+
+bool DeliveryRecord::after(DeliveryId tag) const{
+ return id > tag;
+}
+
+bool DeliveryRecord::coveredBy(const framing::SequenceSet* const range) const{
+ return range->contains(id);
+}
+
+void DeliveryRecord::redeliver(SemanticState* const session) {
+ if (!ended) {
+ if(cancelled){
+ //if subscription was cancelled, requeue it (waiting for
+ //final confirmation for AMQP WG on this case)
+ requeue();
+ }else{
+ msg.payload->redeliver();//mark as redelivered
+ session->deliver(*this);
+ }
+ }
+}
+
+void DeliveryRecord::deliver(framing::FrameHandler& h, DeliveryId deliveryId, uint16_t framesize)
+{
+ id = deliveryId;
+ if (msg.payload->getRedelivered()){
+ msg.payload->getProperties<framing::DeliveryProperties>()->setRedelivered(true);
+ }
+
+ framing::AMQFrame method(framing::in_place<framing::MessageTransferBody>(framing::ProtocolVersion(), tag, acceptExpected ? 0 : 1, acquired ? 0 : 1));
+ method.setEof(false);
+ h.handle(method);
+ msg.payload->sendHeader(h, framesize);
+ msg.payload->sendContent(*queue, h, framesize);
+}
+
+void DeliveryRecord::requeue() const
+{
+ if (acquired && !ended) {
+ msg.payload->redeliver();
+ queue->requeue(msg);
+ }
+}
+
+void DeliveryRecord::release(bool setRedelivered)
+{
+ if (acquired && !ended) {
+ if (setRedelivered) msg.payload->redeliver();
+ queue->requeue(msg);
+ acquired = false;
+ setEnded();
+ } else {
+ QPID_LOG(debug, "Ignoring release for " << id << " acquired=" << acquired << ", ended =" << ended);
+ }
+}
+
+void DeliveryRecord::complete()
+{
+ completed = true;
+}
+
+void DeliveryRecord::accept(TransactionContext* ctxt) {
+ if (acquired && !ended) {
+ queue->dequeue(ctxt, msg);
+ setEnded();
+ QPID_LOG(debug, "Accepted " << id);
+ }
+}
+
+void DeliveryRecord::dequeue(TransactionContext* ctxt) const{
+ if (acquired && !ended) {
+ queue->dequeue(ctxt, msg);
+ }
+}
+
+void DeliveryRecord::committed() const{
+ queue->dequeueCommitted(msg);
+}
+
+void DeliveryRecord::reject()
+{
+ Exchange::shared_ptr alternate = queue->getAlternateExchange();
+ if (alternate) {
+ DeliverableMessage delivery(msg.payload);
+ alternate->route(delivery, msg.payload->getRoutingKey(), msg.payload->getApplicationHeaders());
+ QPID_LOG(info, "Routed rejected message from " << queue->getName() << " to "
+ << alternate->getName());
+ } else {
+ //just drop it
+ QPID_LOG(info, "Dropping rejected message from " << queue->getName());
+ }
+}
+
+uint32_t DeliveryRecord::getCredit() const
+{
+ return credit;
+}
+
+void DeliveryRecord::acquire(DeliveryIds& results) {
+ if (queue->acquire(msg)) {
+ acquired = true;
+ results.push_back(id);
+ } else {
+ QPID_LOG(info, "Message already acquired " << id.getValue());
+ }
+}
+
+void DeliveryRecord::cancel(const std::string& cancelledTag)
+{
+ if (tag == cancelledTag)
+ cancelled = true;
+}
+
+AckRange DeliveryRecord::findRange(DeliveryRecords& records, DeliveryId first, DeliveryId last)
+{
+ ack_iterator start = find_if(records.begin(), records.end(), boost::bind(&DeliveryRecord::matchOrAfter, _1, first));
+ ack_iterator end = start;
+
+ if (start != records.end()) {
+ if (first == last) {
+ //just acked single element (move end past it)
+ ++end;
+ } else {
+ //need to find end (position it just after the last record in range)
+ end = find_if(start, records.end(), boost::bind(&DeliveryRecord::after, _1, last));
+ }
+ }
+ return AckRange(start, end);
+}
+
+
+namespace qpid {
+namespace broker {
+
+std::ostream& operator<<(std::ostream& out, const DeliveryRecord& r)
+{
+ out << "{" << "id=" << r.id.getValue();
+ out << ", tag=" << r.tag << "}";
+ out << ", queue=" << r.queue->getName() << "}";
+ return out;
+}
+
+bool operator<(const DeliveryRecord& a, const DeliveryRecord& b)
+{
+ return a.id < b.id;
+}
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/broker/DeliveryRecord.h b/RC9/qpid/cpp/src/qpid/broker/DeliveryRecord.h
new file mode 100644
index 0000000000..d7ccab0726
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/DeliveryRecord.h
@@ -0,0 +1,141 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _DeliveryRecord_
+#define _DeliveryRecord_
+
+#include <algorithm>
+#include <list>
+#include <vector>
+#include <ostream>
+#include "qpid/framing/SequenceSet.h"
+#include "Queue.h"
+#include "QueuedMessage.h"
+#include "DeliveryId.h"
+#include "Message.h"
+
+namespace qpid {
+namespace broker {
+class SemanticState;
+class DeliveryRecord;
+
+typedef std::list<DeliveryRecord> DeliveryRecords;
+typedef std::list<DeliveryRecord>::iterator ack_iterator;
+
+struct AckRange
+{
+ ack_iterator start;
+ ack_iterator end;
+ AckRange(ack_iterator _start, ack_iterator _end) : start(_start), end(_end) {}
+};
+
+
+/**
+ * Record of a delivery for which an ack is outstanding.
+ */
+class DeliveryRecord
+{
+ QueuedMessage msg;
+ mutable Queue::shared_ptr queue;
+ const std::string tag;
+ DeliveryId id;
+ bool acquired;
+ bool acceptExpected;
+ bool cancelled;
+
+ bool completed;
+ bool ended;
+ const bool windowing;
+
+ /**
+ * Record required credit on construction as the pointer to the
+ * message may be reset once we no longer need to deliver it
+ * (e.g. when it is accepted), but we will still need to be able
+ * to reallocate credit when it is completed (which could happen
+ * after that).
+ */
+ const uint32_t credit;
+
+ public:
+ DeliveryRecord(
+ const QueuedMessage& msg,
+ const Queue::shared_ptr& queue,
+ const std::string& tag,
+ bool acquired,
+ bool accepted,
+ bool windowing,
+ uint32_t credit=0 // Only used if msg is empty.
+ );
+
+ bool matches(DeliveryId tag) const;
+ bool matchOrAfter(DeliveryId tag) const;
+ bool after(DeliveryId tag) const;
+ bool coveredBy(const framing::SequenceSet* const range) const;
+
+ void dequeue(TransactionContext* ctxt = 0) const;
+ void requeue() const;
+ void release(bool setRedelivered);
+ void reject();
+ void cancel(const std::string& tag);
+ void redeliver(SemanticState* const);
+ void acquire(DeliveryIds& results);
+ void complete();
+ void accept(TransactionContext* ctxt);
+ void setEnded();
+ void committed() const;
+
+ bool isAcquired() const { return acquired; }
+ bool isComplete() const { return completed; }
+ bool isRedundant() const { return ended && (!windowing || completed); }
+ bool isCancelled() const { return cancelled; }
+ bool isAccepted() const { return !acceptExpected; }
+ bool isEnded() const { return ended; }
+ bool isWindowing() const { return windowing; }
+
+ uint32_t getCredit() const;
+ const std::string& getTag() const { return tag; }
+
+ void deliver(framing::FrameHandler& h, DeliveryId deliveryId, uint16_t framesize);
+ void setId(DeliveryId _id) { id = _id; }
+
+ static AckRange findRange(DeliveryRecords& records, DeliveryId first, DeliveryId last);
+ const QueuedMessage& getMessage() const { return msg; }
+ framing::SequenceNumber getId() const { return id; }
+ Queue::shared_ptr getQueue() const { return queue; }
+ friend bool operator<(const DeliveryRecord&, const DeliveryRecord&);
+ friend std::ostream& operator<<(std::ostream&, const DeliveryRecord&);
+};
+
+struct AcquireFunctor
+{
+ DeliveryIds& results;
+
+ AcquireFunctor(DeliveryIds& _results) : results(_results) {}
+
+ void operator()(DeliveryRecord& record)
+ {
+ record.acquire(results);
+ }
+};
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/DirectExchange.cpp b/RC9/qpid/cpp/src/qpid/broker/DirectExchange.cpp
new file mode 100644
index 0000000000..2eb488de67
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/DirectExchange.cpp
@@ -0,0 +1,190 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/log/Statement.h"
+#include "DirectExchange.h"
+#include <iostream>
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::sys;
+using qpid::management::Manageable;
+namespace _qmf = qmf::org::apache::qpid::broker;
+
+namespace
+{
+const std::string qpidFedOp("qpid.fed.op");
+const std::string qpidFedTags("qpid.fed.tags");
+const std::string qpidFedOrigin("qpid.fed.origin");
+
+const std::string fedOpBind("B");
+const std::string fedOpUnbind("U");
+const std::string fedOpReorigin("R");
+const std::string fedOpHello("H");
+}
+
+DirectExchange::DirectExchange(const string& _name, Manageable* _parent) : Exchange(_name, _parent)
+{
+ if (mgmtExchange != 0)
+ mgmtExchange->set_type(typeName);
+}
+
+DirectExchange::DirectExchange(const string& _name, bool _durable,
+ const FieldTable& _args, Manageable* _parent) :
+ Exchange(_name, _durable, _args, _parent)
+{
+ if (mgmtExchange != 0)
+ mgmtExchange->set_type(typeName);
+}
+
+bool DirectExchange::bind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* args)
+{
+ string fedOp(args ? args->getAsString(qpidFedOp) : fedOpBind);
+ string fedTags(args ? args->getAsString(qpidFedTags) : "");
+ string fedOrigin(args ? args->getAsString(qpidFedOrigin) : "");
+ bool propagate = false;
+
+ if (args == 0 || fedOp.empty() || fedOp == fedOpBind) {
+ Mutex::ScopedLock l(lock);
+ Binding::shared_ptr b(new Binding(routingKey, queue, this, FieldTable(), fedOrigin));
+ BoundKey& bk = bindings[routingKey];
+ if (bk.queues.add_unless(b, MatchQueue(queue))) {
+ propagate = bk.fedBinding.addOrigin(fedOrigin);
+ if (mgmtExchange != 0) {
+ mgmtExchange->inc_bindingCount();
+ ((_qmf::Queue*) queue->GetManagementObject())->inc_bindingCount();
+ }
+ } else {
+ return false;
+ }
+ } else if (fedOp == fedOpUnbind) {
+ Mutex::ScopedLock l(lock);
+ BoundKey& bk = bindings[routingKey];
+ propagate = bk.fedBinding.delOrigin(fedOrigin);
+ if (bk.fedBinding.count() == 0)
+ unbind(queue, routingKey, 0);
+ } else if (fedOp == fedOpReorigin) {
+ for (std::map<string, BoundKey>::iterator iter = bindings.begin();
+ iter != bindings.end(); iter++) {
+ const BoundKey& bk = iter->second;
+ if (bk.fedBinding.hasLocal()) {
+ propagateFedOp(iter->first, string(), fedOpBind, string());
+ }
+ }
+ }
+
+ routeIVE();
+ if (propagate)
+ propagateFedOp(routingKey, fedTags, fedOp, fedOrigin);
+ return true;
+}
+
+bool DirectExchange::unbind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* /*args*/)
+{
+ bool propagate = false;
+
+ {
+ Mutex::ScopedLock l(lock);
+ BoundKey& bk = bindings[routingKey];
+ if (bk.queues.remove_if(MatchQueue(queue))) {
+ propagate = bk.fedBinding.delOrigin();
+ if (mgmtExchange != 0) {
+ mgmtExchange->dec_bindingCount();
+ ((_qmf::Queue*) queue->GetManagementObject())->dec_bindingCount();
+ }
+ } else {
+ return false;
+ }
+ }
+
+ if (propagate)
+ propagateFedOp(routingKey, string(), fedOpUnbind, string());
+ return true;
+}
+
+void DirectExchange::route(Deliverable& msg, const string& routingKey, const FieldTable* /*args*/)
+{
+ PreRoute pr(msg, this);
+ Queues::ConstPtr p;
+ {
+ Mutex::ScopedLock l(lock);
+ p = bindings[routingKey].queues.snapshot();
+ }
+ int count(0);
+
+ if (p) {
+ for(std::vector<Binding::shared_ptr>::const_iterator i = p->begin(); i != p->end(); i++, count++) {
+ msg.deliverTo((*i)->queue);
+ if ((*i)->mgmtBinding != 0)
+ (*i)->mgmtBinding->inc_msgMatched();
+ }
+ }
+
+ if(!count){
+ QPID_LOG(info, "DirectExchange " << getName() << " could not route message with key " << routingKey
+ << "; no matching binding found");
+ if (mgmtExchange != 0) {
+ mgmtExchange->inc_msgDrops();
+ mgmtExchange->inc_byteDrops(msg.contentSize());
+ }
+ } else {
+ if (mgmtExchange != 0) {
+ mgmtExchange->inc_msgRoutes(count);
+ mgmtExchange->inc_byteRoutes(count * msg.contentSize());
+ }
+ }
+
+ if (mgmtExchange != 0) {
+ mgmtExchange->inc_msgReceives();
+ mgmtExchange->inc_byteReceives(msg.contentSize());
+ }
+}
+
+
+bool DirectExchange::isBound(Queue::shared_ptr queue, const string* const routingKey, const FieldTable* const)
+{
+ Mutex::ScopedLock l(lock);
+ if (routingKey) {
+ Bindings::iterator i = bindings.find(*routingKey);
+
+ if (i == bindings.end())
+ return false;
+ if (!queue)
+ return true;
+
+ Queues::ConstPtr p = i->second.queues.snapshot();
+ return p && std::find_if(p->begin(), p->end(), MatchQueue(queue)) != p->end();
+ } else if (!queue) {
+ //if no queue or routing key is specified, just report whether any bindings exist
+ return bindings.size() > 0;
+ } else {
+ for (Bindings::iterator i = bindings.begin(); i != bindings.end(); i++) {
+ Queues::ConstPtr p = i->second.queues.snapshot();
+ if (p && std::find_if(p->begin(), p->end(), MatchQueue(queue)) != p->end()) return true;
+ }
+ return false;
+ }
+
+ return false;
+}
+
+DirectExchange::~DirectExchange() {}
+
+const std::string DirectExchange::typeName("direct");
diff --git a/RC9/qpid/cpp/src/qpid/broker/DirectExchange.h b/RC9/qpid/cpp/src/qpid/broker/DirectExchange.h
new file mode 100644
index 0000000000..ba60469df8
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/DirectExchange.h
@@ -0,0 +1,65 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _DirectExchange_
+#define _DirectExchange_
+
+#include <map>
+#include <vector>
+#include "Exchange.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/sys/CopyOnWriteArray.h"
+#include "qpid/sys/Mutex.h"
+#include "Queue.h"
+
+namespace qpid {
+namespace broker {
+class DirectExchange : public virtual Exchange {
+ typedef qpid::sys::CopyOnWriteArray<Binding::shared_ptr> Queues;
+ struct BoundKey {
+ Queues queues;
+ FedBinding fedBinding;
+ };
+ typedef std::map<string, BoundKey> Bindings;
+ Bindings bindings;
+ qpid::sys::Mutex lock;
+
+public:
+ static const std::string typeName;
+
+ DirectExchange(const std::string& name, management::Manageable* parent = 0);
+ DirectExchange(const string& _name, bool _durable,
+ const qpid::framing::FieldTable& _args, management::Manageable* parent = 0);
+
+ virtual std::string getType() const { return typeName; }
+
+ virtual bool bind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args);
+ virtual bool unbind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args);
+ virtual void route(Deliverable& msg, const std::string& routingKey, const qpid::framing::FieldTable* args);
+ virtual bool isBound(Queue::shared_ptr queue, const string* const routingKey, const qpid::framing::FieldTable* const args);
+
+ virtual ~DirectExchange();
+
+ virtual bool supportsDynamicBinding() { return true; }
+};
+
+}}
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/DtxAck.cpp b/RC9/qpid/cpp/src/qpid/broker/DtxAck.cpp
new file mode 100644
index 0000000000..bc7d662afb
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/DtxAck.cpp
@@ -0,0 +1,59 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "DtxAck.h"
+#include "qpid/log/Statement.h"
+
+using std::bind1st;
+using std::bind2nd;
+using std::mem_fun_ref;
+using namespace qpid::broker;
+
+DtxAck::DtxAck(const qpid::framing::SequenceSet& acked, std::list<DeliveryRecord>& unacked)
+{
+ remove_copy_if(unacked.begin(), unacked.end(), inserter(pending, pending.end()),
+ not1(bind2nd(mem_fun_ref(&DeliveryRecord::coveredBy), &acked)));
+}
+
+bool DtxAck::prepare(TransactionContext* ctxt) throw()
+{
+ try{
+ //record dequeue in the store
+ for (ack_iterator i = pending.begin(); i != pending.end(); i++) {
+ i->dequeue(ctxt);
+ }
+ return true;
+ }catch(...){
+ QPID_LOG(error, "Failed to prepare");
+ return false;
+ }
+}
+
+void DtxAck::commit() throw()
+{
+ for_each(pending.begin(), pending.end(), mem_fun_ref(&DeliveryRecord::committed));
+ pending.clear();
+}
+
+void DtxAck::rollback() throw()
+{
+ for_each(pending.begin(), pending.end(), mem_fun_ref(&DeliveryRecord::requeue));
+ pending.clear();
+}
diff --git a/RC9/qpid/cpp/src/qpid/broker/DtxAck.h b/RC9/qpid/cpp/src/qpid/broker/DtxAck.h
new file mode 100644
index 0000000000..d43532906a
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/DtxAck.h
@@ -0,0 +1,48 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _DtxAck_
+#define _DtxAck_
+
+#include <algorithm>
+#include <functional>
+#include <list>
+#include "qpid/framing/SequenceSet.h"
+#include "DeliveryRecord.h"
+#include "TxOp.h"
+
+namespace qpid {
+ namespace broker {
+ class DtxAck : public TxOp{
+ std::list<DeliveryRecord> pending;
+
+ public:
+ DtxAck(const framing::SequenceSet& acked, std::list<DeliveryRecord>& unacked);
+ virtual bool prepare(TransactionContext* ctxt) throw();
+ virtual void commit() throw();
+ virtual void rollback() throw();
+ virtual ~DtxAck(){}
+ virtual void accept(TxOpConstVisitor& visitor) const { visitor(*this); }
+ };
+ }
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/DtxBuffer.cpp b/RC9/qpid/cpp/src/qpid/broker/DtxBuffer.cpp
new file mode 100644
index 0000000000..29a07ea6d9
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/DtxBuffer.cpp
@@ -0,0 +1,83 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "DtxBuffer.h"
+
+using namespace qpid::broker;
+using qpid::sys::Mutex;
+
+DtxBuffer::DtxBuffer(const std::string& _xid)
+ : xid(_xid), ended(false), suspended(false), failed(false), expired(false) {}
+
+DtxBuffer::~DtxBuffer() {}
+
+void DtxBuffer::markEnded()
+{
+ Mutex::ScopedLock locker(lock);
+ ended = true;
+}
+
+bool DtxBuffer::isEnded()
+{
+ Mutex::ScopedLock locker(lock);
+ return ended;
+}
+
+void DtxBuffer::setSuspended(bool isSuspended)
+{
+ suspended = isSuspended;
+}
+
+bool DtxBuffer::isSuspended()
+{
+ return suspended;
+}
+
+void DtxBuffer::fail()
+{
+ Mutex::ScopedLock locker(lock);
+ rollback();
+ failed = true;
+ ended = true;
+}
+
+bool DtxBuffer::isRollbackOnly()
+{
+ Mutex::ScopedLock locker(lock);
+ return failed;
+}
+
+const std::string& DtxBuffer::getXid()
+{
+ return xid;
+}
+
+void DtxBuffer::timedout()
+{
+ Mutex::ScopedLock locker(lock);
+ expired = true;
+ fail();
+}
+
+bool DtxBuffer::isExpired()
+{
+ Mutex::ScopedLock locker(lock);
+ return expired;
+}
diff --git a/RC9/qpid/cpp/src/qpid/broker/DtxBuffer.h b/RC9/qpid/cpp/src/qpid/broker/DtxBuffer.h
new file mode 100644
index 0000000000..b302632037
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/DtxBuffer.h
@@ -0,0 +1,56 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _DtxBuffer_
+#define _DtxBuffer_
+
+#include "TxBuffer.h"
+#include "qpid/sys/Mutex.h"
+
+namespace qpid {
+ namespace broker {
+ class DtxBuffer : public TxBuffer{
+ sys::Mutex lock;
+ const std::string xid;
+ bool ended;
+ bool suspended;
+ bool failed;
+ bool expired;
+
+ public:
+ typedef boost::shared_ptr<DtxBuffer> shared_ptr;
+
+ DtxBuffer(const std::string& xid = "");
+ ~DtxBuffer();
+ void markEnded();
+ bool isEnded();
+ void setSuspended(bool suspended);
+ bool isSuspended();
+ void fail();
+ bool isRollbackOnly();
+ void timedout();
+ bool isExpired();
+ const std::string& getXid();
+ };
+ }
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/DtxManager.cpp b/RC9/qpid/cpp/src/qpid/broker/DtxManager.cpp
new file mode 100644
index 0000000000..f4494fccc6
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/DtxManager.cpp
@@ -0,0 +1,171 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "DtxManager.h"
+#include "DtxTimeout.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/log/Statement.h"
+#include "qpid/ptr_map.h"
+
+#include <boost/format.hpp>
+#include <iostream>
+
+using boost::intrusive_ptr;
+using qpid::sys::Mutex;
+using qpid::ptr_map_ptr;
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+DtxManager::DtxManager(Timer& t) : store(0), timer(t) {}
+
+DtxManager::~DtxManager() {}
+
+void DtxManager::start(const std::string& xid, DtxBuffer::shared_ptr ops)
+{
+ createWork(xid)->add(ops);
+}
+
+void DtxManager::join(const std::string& xid, DtxBuffer::shared_ptr ops)
+{
+ getWork(xid)->add(ops);
+}
+
+void DtxManager::recover(const std::string& xid, std::auto_ptr<TPCTransactionContext> txn, DtxBuffer::shared_ptr ops)
+{
+ createWork(xid)->recover(txn, ops);
+}
+
+bool DtxManager::prepare(const std::string& xid)
+{
+ QPID_LOG(debug, "preparing: " << xid);
+ try {
+ return getWork(xid)->prepare();
+ } catch (DtxTimeoutException& e) {
+ remove(xid);
+ throw e;
+ }
+}
+
+bool DtxManager::commit(const std::string& xid, bool onePhase)
+{
+ QPID_LOG(debug, "committing: " << xid);
+ try {
+ bool result = getWork(xid)->commit(onePhase);
+ remove(xid);
+ return result;
+ } catch (DtxTimeoutException& e) {
+ remove(xid);
+ throw e;
+ }
+}
+
+void DtxManager::rollback(const std::string& xid)
+{
+ QPID_LOG(debug, "rolling back: " << xid);
+ try {
+ getWork(xid)->rollback();
+ remove(xid);
+ } catch (DtxTimeoutException& e) {
+ remove(xid);
+ throw e;
+ }
+}
+
+DtxWorkRecord* DtxManager::getWork(const std::string& xid)
+{
+ Mutex::ScopedLock locker(lock);
+ WorkMap::iterator i = work.find(xid);
+ if (i == work.end()) {
+ throw NotFoundException(QPID_MSG("Unrecognised xid " << xid));
+ }
+ return ptr_map_ptr(i);
+}
+
+void DtxManager::remove(const std::string& xid)
+{
+ Mutex::ScopedLock locker(lock);
+ WorkMap::iterator i = work.find(xid);
+ if (i == work.end()) {
+ throw NotFoundException(QPID_MSG("Unrecognised xid " << xid));
+ } else {
+ work.erase(i);
+ }
+}
+
+DtxWorkRecord* DtxManager::createWork(std::string xid)
+{
+ Mutex::ScopedLock locker(lock);
+ WorkMap::iterator i = work.find(xid);
+ if (i != work.end()) {
+ throw NotAllowedException(QPID_MSG("Xid " << xid << " is already known (use 'join' to add work to an existing xid)"));
+ } else {
+ return ptr_map_ptr(work.insert(xid, new DtxWorkRecord(xid, store)).first);
+ }
+}
+
+void DtxManager::setTimeout(const std::string& xid, uint32_t secs)
+{
+ DtxWorkRecord* record = getWork(xid);
+ intrusive_ptr<DtxTimeout> timeout = record->getTimeout();
+ if (timeout.get()) {
+ if (timeout->timeout == secs) return;//no need to do anything further if timeout hasn't changed
+ timeout->cancelled = true;
+ }
+ timeout = intrusive_ptr<DtxTimeout>(new DtxTimeout(secs, *this, xid));
+ record->setTimeout(timeout);
+ timer.add(boost::static_pointer_cast<TimerTask>(timeout));
+
+}
+
+uint32_t DtxManager::getTimeout(const std::string& xid)
+{
+ intrusive_ptr<DtxTimeout> timeout = getWork(xid)->getTimeout();
+ return !timeout ? 0 : timeout->timeout;
+}
+
+void DtxManager::timedout(const std::string& xid)
+{
+ Mutex::ScopedLock locker(lock);
+ WorkMap::iterator i = work.find(xid);
+ if (i == work.end()) {
+ QPID_LOG(warning, "Transaction timeout failed: no record for xid");
+ } else {
+ ptr_map_ptr(i)->timedout();
+ //TODO: do we want to have a timed task to cleanup, or can we rely on an explicit completion?
+ //timer.add(intrusive_ptr<TimerTask>(new DtxCleanup(60*30/*30 mins*/, *this, xid)));
+ }
+}
+
+DtxManager::DtxCleanup::DtxCleanup(uint32_t _timeout, DtxManager& _mgr, const std::string& _xid)
+ : TimerTask(qpid::sys::Duration(_timeout * qpid::sys::TIME_SEC)), mgr(_mgr), xid(_xid) {}
+
+void DtxManager::DtxCleanup::fire()
+{
+ try {
+ mgr.remove(xid);
+ } catch (ConnectionException& /*e*/) {
+ //assume it was explicitly cleaned up after a call to prepare, commit or rollback
+ }
+}
+
+void DtxManager::setStore (TransactionalStore* _store)
+{
+ store = _store;
+}
diff --git a/RC9/qpid/cpp/src/qpid/broker/DtxManager.h b/RC9/qpid/cpp/src/qpid/broker/DtxManager.h
new file mode 100644
index 0000000000..a61e8610f0
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/DtxManager.h
@@ -0,0 +1,74 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _DtxManager_
+#define _DtxManager_
+
+#include <boost/ptr_container/ptr_map.hpp>
+#include "DtxBuffer.h"
+#include "DtxWorkRecord.h"
+#include "Timer.h"
+#include "TransactionalStore.h"
+#include "qpid/framing/amqp_types.h"
+#include "qpid/sys/Mutex.h"
+
+namespace qpid {
+namespace broker {
+
+class DtxManager{
+ typedef boost::ptr_map<std::string, DtxWorkRecord> WorkMap;
+
+ struct DtxCleanup : public TimerTask
+ {
+ DtxManager& mgr;
+ const std::string& xid;
+
+ DtxCleanup(uint32_t timeout, DtxManager& mgr, const std::string& xid);
+ void fire();
+ };
+
+ WorkMap work;
+ TransactionalStore* store;
+ qpid::sys::Mutex lock;
+ Timer& timer;
+
+ void remove(const std::string& xid);
+ DtxWorkRecord* getWork(const std::string& xid);
+ DtxWorkRecord* createWork(std::string xid);
+
+public:
+ DtxManager(Timer&);
+ ~DtxManager();
+ void start(const std::string& xid, DtxBuffer::shared_ptr work);
+ void join(const std::string& xid, DtxBuffer::shared_ptr work);
+ void recover(const std::string& xid, std::auto_ptr<TPCTransactionContext> txn, DtxBuffer::shared_ptr work);
+ bool prepare(const std::string& xid);
+ bool commit(const std::string& xid, bool onePhase);
+ void rollback(const std::string& xid);
+ void setTimeout(const std::string& xid, uint32_t secs);
+ uint32_t getTimeout(const std::string& xid);
+ void timedout(const std::string& xid);
+ void setStore(TransactionalStore* store);
+};
+
+}
+}
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/DtxTimeout.cpp b/RC9/qpid/cpp/src/qpid/broker/DtxTimeout.cpp
new file mode 100644
index 0000000000..8e0a7741c4
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/DtxTimeout.cpp
@@ -0,0 +1,35 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "DtxTimeout.h"
+#include "DtxManager.h"
+#include "qpid/sys/Time.h"
+
+using namespace qpid::broker;
+
+DtxTimeout::DtxTimeout(uint32_t _timeout, DtxManager& _mgr, const std::string& _xid)
+ : TimerTask(qpid::sys::Duration(_timeout * qpid::sys::TIME_SEC)), timeout(_timeout), mgr(_mgr), xid(_xid)
+{
+}
+
+void DtxTimeout::fire()
+{
+ mgr.timedout(xid);
+}
diff --git a/RC9/qpid/cpp/src/qpid/broker/DtxTimeout.h b/RC9/qpid/cpp/src/qpid/broker/DtxTimeout.h
new file mode 100644
index 0000000000..6e949eab0d
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/DtxTimeout.h
@@ -0,0 +1,48 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _DtxTimeout_
+#define _DtxTimeout_
+
+#include "qpid/Exception.h"
+#include "Timer.h"
+
+namespace qpid {
+namespace broker {
+
+class DtxManager;
+
+struct DtxTimeoutException : public Exception {};
+
+struct DtxTimeout : public TimerTask
+{
+ const uint32_t timeout;
+ DtxManager& mgr;
+ const std::string xid;
+
+ DtxTimeout(uint32_t timeout, DtxManager& mgr, const std::string& xid);
+ void fire();
+};
+
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/DtxWorkRecord.cpp b/RC9/qpid/cpp/src/qpid/broker/DtxWorkRecord.cpp
new file mode 100644
index 0000000000..cc79813dab
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/DtxWorkRecord.cpp
@@ -0,0 +1,177 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "DtxWorkRecord.h"
+#include "qpid/framing/reply_exceptions.h"
+#include <boost/format.hpp>
+#include <boost/mem_fn.hpp>
+using boost::mem_fn;
+using qpid::sys::Mutex;
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+DtxWorkRecord::DtxWorkRecord(const std::string& _xid, TransactionalStore* const _store) :
+ xid(_xid), store(_store), completed(false), rolledback(false), prepared(false), expired(false) {}
+
+DtxWorkRecord::~DtxWorkRecord()
+{
+ if (timeout.get()) {
+ timeout->cancelled = true;
+ }
+}
+
+bool DtxWorkRecord::prepare()
+{
+ Mutex::ScopedLock locker(lock);
+ if (check()) {
+ txn = store->begin(xid);
+ if (prepare(txn.get())) {
+ store->prepare(*txn);
+ prepared = true;
+ } else {
+ abort();
+ //TODO: this should probably be flagged as internal error
+ }
+ } else {
+ //some part of the work has been marked rollback only
+ abort();
+ }
+ return prepared;
+}
+
+bool DtxWorkRecord::prepare(TransactionContext* _txn)
+{
+ bool succeeded(true);
+ for (Work::iterator i = work.begin(); succeeded && i != work.end(); i++) {
+ succeeded = (*i)->prepare(_txn);
+ }
+ return succeeded;
+}
+
+bool DtxWorkRecord::commit(bool onePhase)
+{
+ Mutex::ScopedLock locker(lock);
+ if (check()) {
+ if (prepared) {
+ //already prepared i.e. 2pc
+ if (onePhase) {
+ throw IllegalStateException(QPID_MSG("Branch with xid " << xid << " has been prepared, one-phase option not valid!"));
+ }
+
+ store->commit(*txn);
+ txn.reset();
+
+ std::for_each(work.begin(), work.end(), mem_fn(&TxBuffer::commit));
+ return true;
+ } else {
+ //1pc commit optimisation, don't need a 2pc transaction context:
+ if (!onePhase) {
+ throw IllegalStateException(QPID_MSG("Branch with xid " << xid << " has not been prepared, one-phase option required!"));
+ }
+ std::auto_ptr<TransactionContext> localtxn = store->begin();
+ if (prepare(localtxn.get())) {
+ store->commit(*localtxn);
+ std::for_each(work.begin(), work.end(), mem_fn(&TxBuffer::commit));
+ return true;
+ } else {
+ store->abort(*localtxn);
+ abort();
+ //TODO: this should probably be flagged as internal error
+ return false;
+ }
+ }
+ } else {
+ //some part of the work has been marked rollback only
+ abort();
+ return false;
+ }
+}
+
+void DtxWorkRecord::rollback()
+{
+ Mutex::ScopedLock locker(lock);
+ check();
+ abort();
+}
+
+void DtxWorkRecord::add(DtxBuffer::shared_ptr ops)
+{
+ Mutex::ScopedLock locker(lock);
+ if (expired) {
+ throw DtxTimeoutException();
+ }
+ if (completed) {
+ throw CommandInvalidException(QPID_MSG("Branch with xid " << xid << " has been completed!"));
+ }
+ work.push_back(ops);
+}
+
+bool DtxWorkRecord::check()
+{
+ if (expired) {
+ throw DtxTimeoutException();
+ }
+ if (!completed) {
+ //iterate through all DtxBuffers and ensure they are all ended
+ for (Work::iterator i = work.begin(); i != work.end(); i++) {
+ if (!(*i)->isEnded()) {
+ throw IllegalStateException(QPID_MSG("Branch with xid " << xid << " not completed!"));
+ } else if ((*i)->isRollbackOnly()) {
+ rolledback = true;
+ }
+ }
+ completed = true;
+ }
+ return !rolledback;
+}
+
+void DtxWorkRecord::abort()
+{
+ if (txn.get()) {
+ store->abort(*txn);
+ txn.reset();
+ }
+ std::for_each(work.begin(), work.end(), mem_fn(&TxBuffer::rollback));
+}
+
+void DtxWorkRecord::recover(std::auto_ptr<TPCTransactionContext> _txn, DtxBuffer::shared_ptr ops)
+{
+ add(ops);
+ txn = _txn;
+ ops->markEnded();
+ completed = true;
+ prepared = true;
+}
+
+void DtxWorkRecord::timedout()
+{
+ Mutex::ScopedLock locker(lock);
+ expired = true;
+ rolledback = true;
+ if (!completed) {
+ for (Work::iterator i = work.begin(); i != work.end(); i++) {
+ if (!(*i)->isEnded()) {
+ (*i)->timedout();
+ }
+ }
+ }
+ abort();
+}
diff --git a/RC9/qpid/cpp/src/qpid/broker/DtxWorkRecord.h b/RC9/qpid/cpp/src/qpid/broker/DtxWorkRecord.h
new file mode 100644
index 0000000000..6677784c32
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/DtxWorkRecord.h
@@ -0,0 +1,79 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _DtxWorkRecord_
+#define _DtxWorkRecord_
+
+#include "DtxBuffer.h"
+#include "DtxTimeout.h"
+#include "TransactionalStore.h"
+
+#include "qpid/framing/amqp_types.h"
+#include "qpid/sys/Mutex.h"
+
+#include <algorithm>
+#include <functional>
+#include <vector>
+
+#include <boost/intrusive_ptr.hpp>
+
+namespace qpid {
+namespace broker {
+
+/**
+ * Represents the work done under a particular distributed transaction
+ * across potentially multiple channels. Identified by a xid. Allows
+ * that work to be prepared, committed and rolled-back.
+ */
+class DtxWorkRecord
+{
+ typedef std::vector<DtxBuffer::shared_ptr> Work;
+
+ const std::string xid;
+ TransactionalStore* const store;
+ bool completed;
+ bool rolledback;
+ bool prepared;
+ bool expired;
+ boost::intrusive_ptr<DtxTimeout> timeout;
+ Work work;
+ std::auto_ptr<TPCTransactionContext> txn;
+ qpid::sys::Mutex lock;
+
+ bool check();
+ void abort();
+ bool prepare(TransactionContext* txn);
+public:
+ DtxWorkRecord(const std::string& xid, TransactionalStore* const store);
+ ~DtxWorkRecord();
+ bool prepare();
+ bool commit(bool onePhase);
+ void rollback();
+ void add(DtxBuffer::shared_ptr ops);
+ void recover(std::auto_ptr<TPCTransactionContext> txn, DtxBuffer::shared_ptr ops);
+ void timedout();
+ void setTimeout(boost::intrusive_ptr<DtxTimeout> t) { timeout = t; }
+ boost::intrusive_ptr<DtxTimeout> getTimeout() { return timeout; }
+};
+
+}
+}
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/Exchange.cpp b/RC9/qpid/cpp/src/qpid/broker/Exchange.cpp
new file mode 100644
index 0000000000..34673bdab3
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/Exchange.cpp
@@ -0,0 +1,270 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Exchange.h"
+#include "ExchangeRegistry.h"
+#include "qpid/agent/ManagementAgent.h"
+#include "qpid/log/Statement.h"
+#include "qpid/framing/MessageProperties.h"
+#include "DeliverableMessage.h"
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+using qpid::framing::Buffer;
+using qpid::framing::FieldTable;
+using qpid::sys::Mutex;
+using qpid::management::ManagementAgent;
+using qpid::management::ManagementObject;
+using qpid::management::Manageable;
+using qpid::management::Args;
+namespace _qmf = qmf::org::apache::qpid::broker;
+
+namespace
+{
+const std::string qpidMsgSequence("qpid.msg_sequence");
+const std::string qpidSequenceCounter("qpid.sequence_counter");
+const std::string qpidIVE("qpid.ive");
+const std::string qpidFedOp("qpid.fed.op");
+const std::string qpidFedTags("qpid.fed.tags");
+const std::string qpidFedOrigin("qpid.fed.origin");
+
+const std::string fedOpBind("B");
+const std::string fedOpUnbind("U");
+const std::string fedOpReorigin("R");
+const std::string fedOpHello("H");
+}
+
+
+Exchange::PreRoute::PreRoute(Deliverable& msg, Exchange* _p):parent(_p) {
+ if (parent){
+ if (parent->sequence || parent->ive) parent->sequenceLock.lock();
+
+ if (parent->sequence){
+ parent->sequenceNo++;
+ msg.getMessage().getProperties<MessageProperties>()->getApplicationHeaders().setInt64(qpidMsgSequence,parent->sequenceNo);
+ }
+ if (parent->ive) {
+ parent->lastMsg = &( msg.getMessage());
+ }
+ }
+}
+
+Exchange::PreRoute::~PreRoute(){
+ if (parent && (parent->sequence || parent->ive)){
+ parent->sequenceLock.unlock();
+ }
+}
+
+void Exchange::routeIVE(){
+ if (ive && lastMsg.get()){
+ DeliverableMessage dmsg(lastMsg);
+ route(dmsg, lastMsg->getRoutingKey(), lastMsg->getApplicationHeaders());
+ }
+}
+
+
+Exchange::Exchange (const string& _name, Manageable* parent) :
+ name(_name), durable(false), persistenceId(0), sequence(false),
+ sequenceNo(0), ive(false), mgmtExchange(0)
+{
+ if (parent != 0)
+ {
+ ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+ if (agent != 0)
+ {
+ mgmtExchange = new _qmf::Exchange (agent, this, parent, _name, durable);
+ agent->addObject (mgmtExchange);
+ }
+ }
+}
+
+Exchange::Exchange(const string& _name, bool _durable, const qpid::framing::FieldTable& _args,
+ Manageable* parent)
+ : name(_name), durable(_durable), args(_args), alternateUsers(0), persistenceId(0),
+ sequence(false), sequenceNo(0), ive(false), mgmtExchange(0)
+{
+ if (parent != 0)
+ {
+ ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+ if (agent != 0)
+ {
+ mgmtExchange = new _qmf::Exchange (agent, this, parent, _name, durable);
+ mgmtExchange->set_arguments(args);
+ if (!durable) {
+ if (name == "")
+ agent->addObject (mgmtExchange, 0x1000000000000004LL); // Special default exchange ID
+ else if (name == "qpid.management")
+ agent->addObject (mgmtExchange, 0x1000000000000005LL); // Special management exchange ID
+ else
+ agent->addObject (mgmtExchange);
+ }
+ }
+ }
+
+ sequence = _args.get(qpidMsgSequence);
+ if (sequence) {
+ QPID_LOG(debug, "Configured exchange "+ _name +" with Msg sequencing");
+ args.setInt64(std::string(qpidSequenceCounter), sequenceNo);
+ }
+
+ ive = _args.get(qpidIVE);
+ if (ive) QPID_LOG(debug, "Configured exchange "+ _name +" with Initial Value");
+}
+
+Exchange::~Exchange ()
+{
+ if (mgmtExchange != 0)
+ mgmtExchange->resourceDestroy ();
+}
+
+void Exchange::setPersistenceId(uint64_t id) const
+{
+ if (mgmtExchange != 0 && persistenceId == 0)
+ {
+ ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+ agent->addObject (mgmtExchange, 0x2000000000000000LL + id);
+ }
+ persistenceId = id;
+}
+
+Exchange::shared_ptr Exchange::decode(ExchangeRegistry& exchanges, Buffer& buffer)
+{
+ string name;
+ string type;
+ FieldTable args;
+
+ buffer.getShortString(name);
+ bool durable(buffer.getOctet());
+ buffer.getShortString(type);
+ buffer.get(args);
+
+ Exchange::shared_ptr exch = exchanges.declare(name, type, durable, args).first;
+ exch->sequenceNo = args.getAsInt64(qpidSequenceCounter);
+ return exch;
+}
+
+void Exchange::encode(Buffer& buffer) const
+{
+ buffer.putShortString(name);
+ buffer.putOctet(durable);
+ buffer.putShortString(getType());
+ if (args.isSet(qpidSequenceCounter))
+ args.setInt64(std::string(qpidSequenceCounter),sequenceNo);
+ buffer.put(args);
+}
+
+uint32_t Exchange::encodedSize() const
+{
+ return name.size() + 1/*short string size*/
+ + 1 /*durable*/
+ + getType().size() + 1/*short string size*/
+ + args.encodedSize();
+}
+
+ManagementObject* Exchange::GetManagementObject (void) const
+{
+ return (ManagementObject*) mgmtExchange;
+}
+
+void Exchange::registerDynamicBridge(DynamicBridge* db)
+{
+ if (!supportsDynamicBinding())
+ throw Exception("Exchange type does not support dynamic binding");
+
+ {
+ Mutex::ScopedLock l(bridgeLock);
+ for (std::vector<DynamicBridge*>::iterator iter = bridgeVector.begin();
+ iter != bridgeVector.end(); iter++)
+ (*iter)->sendReorigin();
+
+ bridgeVector.push_back(db);
+ }
+
+ FieldTable args;
+ args.setString(qpidFedOp, fedOpReorigin);
+ bind(Queue::shared_ptr(), string(), &args);
+}
+
+void Exchange::removeDynamicBridge(DynamicBridge* db)
+{
+ Mutex::ScopedLock l(bridgeLock);
+ for (std::vector<DynamicBridge*>::iterator iter = bridgeVector.begin();
+ iter != bridgeVector.end(); iter++)
+ if (*iter == db) {
+ bridgeVector.erase(iter);
+ break;
+ }
+}
+
+void Exchange::handleHelloRequest()
+{
+}
+
+void Exchange::propagateFedOp(const string& routingKey, const string& tags, const string& op, const string& origin)
+{
+ Mutex::ScopedLock l(bridgeLock);
+ string myOp(op.empty() ? fedOpBind : op);
+
+ for (std::vector<DynamicBridge*>::iterator iter = bridgeVector.begin();
+ iter != bridgeVector.end(); iter++)
+ (*iter)->propagateBinding(routingKey, tags, op, origin);
+}
+
+Exchange::Binding::Binding(const string& _key, Queue::shared_ptr _queue, Exchange* parent,
+ FieldTable _args, const string& origin)
+ : queue(_queue), key(_key), args(_args), mgmtBinding(0)
+{
+ if (parent != 0)
+ {
+ ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+ if (agent != 0)
+ {
+ ManagementObject* mo = queue->GetManagementObject();
+ if (mo != 0)
+ {
+ management::ObjectId queueId = mo->getObjectId();
+ mgmtBinding = new _qmf::Binding
+ (agent, this, (Manageable*) parent, queueId, key, args);
+ if (!origin.empty())
+ mgmtBinding->set_origin(origin);
+ agent->addObject (mgmtBinding);
+ }
+ }
+ }
+}
+
+Exchange::Binding::~Binding ()
+{
+ if (mgmtBinding != 0)
+ mgmtBinding->resourceDestroy ();
+}
+
+ManagementObject* Exchange::Binding::GetManagementObject () const
+{
+ return (ManagementObject*) mgmtBinding;
+}
+
+Exchange::MatchQueue::MatchQueue(Queue::shared_ptr q) : queue(q) {}
+
+bool Exchange::MatchQueue::operator()(Exchange::Binding::shared_ptr b)
+{
+ return b->queue == queue;
+}
diff --git a/RC9/qpid/cpp/src/qpid/broker/Exchange.h b/RC9/qpid/cpp/src/qpid/broker/Exchange.h
new file mode 100644
index 0000000000..5de3e98bc0
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/Exchange.h
@@ -0,0 +1,178 @@
+#ifndef _broker_Exchange_h
+#define _broker_Exchange_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <boost/shared_ptr.hpp>
+#include "Deliverable.h"
+#include "Queue.h"
+#include "MessageStore.h"
+#include "PersistableExchange.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/management/Manageable.h"
+#include "qmf/org/apache/qpid/broker/Exchange.h"
+#include "qmf/org/apache/qpid/broker/Binding.h"
+
+namespace qpid {
+namespace broker {
+
+class ExchangeRegistry;
+
+class Exchange : public PersistableExchange, public management::Manageable {
+private:
+ const std::string name;
+ const bool durable;
+ mutable qpid::framing::FieldTable args;
+ boost::shared_ptr<Exchange> alternate;
+ uint32_t alternateUsers;
+ mutable uint64_t persistenceId;
+
+protected:
+ bool sequence;
+ mutable qpid::sys::Mutex sequenceLock;
+ int64_t sequenceNo;
+ bool ive;
+ boost::intrusive_ptr<Message> lastMsg;
+
+ class PreRoute{
+ public:
+ PreRoute(Deliverable& msg, Exchange* _p);
+ ~PreRoute();
+ private:
+ Exchange* parent;
+ };
+
+ void routeIVE();
+
+ struct Binding : public management::Manageable {
+ typedef boost::shared_ptr<Binding> shared_ptr;
+ typedef std::vector<Binding::shared_ptr> vector;
+
+ Queue::shared_ptr queue;
+ const std::string key;
+ const framing::FieldTable args;
+ qmf::org::apache::qpid::broker::Binding* mgmtBinding;
+
+ Binding(const std::string& key, Queue::shared_ptr queue, Exchange* parent = 0,
+ framing::FieldTable args = framing::FieldTable(), const std::string& origin = std::string());
+ ~Binding();
+ management::ManagementObject* GetManagementObject() const;
+ };
+
+ struct MatchQueue {
+ const Queue::shared_ptr queue;
+ MatchQueue(Queue::shared_ptr q);
+ bool operator()(Exchange::Binding::shared_ptr b);
+ };
+
+ class FedBinding {
+ uint32_t localBindings;
+ std::set<std::string> originSet;
+ public:
+ FedBinding() : localBindings(0) {}
+ bool hasLocal() const { return localBindings != 0; }
+ bool addOrigin(const std::string& origin) {
+ if (origin.empty()) {
+ localBindings++;
+ return localBindings == 1;
+ }
+ originSet.insert(origin);
+ return true;
+ }
+ bool delOrigin(const std::string& origin) {
+ originSet.erase(origin);
+ return true;
+ }
+ bool delOrigin() {
+ if (localBindings > 0)
+ localBindings--;
+ return localBindings == 0;
+ }
+ uint32_t count() {
+ return localBindings + originSet.size();
+ }
+ };
+
+ qmf::org::apache::qpid::broker::Exchange* mgmtExchange;
+
+public:
+ typedef boost::shared_ptr<Exchange> shared_ptr;
+
+ explicit Exchange(const std::string& name, management::Manageable* parent = 0);
+ Exchange(const std::string& _name, bool _durable, const qpid::framing::FieldTable& _args,
+ management::Manageable* parent = 0);
+ virtual ~Exchange();
+
+ const std::string& getName() const { return name; }
+ bool isDurable() { return durable; }
+ qpid::framing::FieldTable& getArgs() { return args; }
+
+ Exchange::shared_ptr getAlternate() { return alternate; }
+ void setAlternate(Exchange::shared_ptr _alternate) { alternate = _alternate; }
+ void incAlternateUsers() { alternateUsers++; }
+ void decAlternateUsers() { alternateUsers--; }
+ bool inUseAsAlternate() { return alternateUsers > 0; }
+
+ virtual std::string getType() const = 0;
+ virtual bool bind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args) = 0;
+ virtual bool unbind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args) = 0;
+ virtual bool isBound(Queue::shared_ptr queue, const std::string* const routingKey, const qpid::framing::FieldTable* const args) = 0;
+ virtual void route(Deliverable& msg, const std::string& routingKey, const qpid::framing::FieldTable* args) = 0;
+
+ //PersistableExchange:
+ void setPersistenceId(uint64_t id) const;
+ uint64_t getPersistenceId() const { return persistenceId; }
+ uint32_t encodedSize() const;
+ void encode(framing::Buffer& buffer) const;
+
+ static Exchange::shared_ptr decode(ExchangeRegistry& exchanges, framing::Buffer& buffer);
+
+ // Manageable entry points
+ management::ManagementObject* GetManagementObject(void) const;
+
+ // Federation hooks
+ class DynamicBridge {
+ public:
+ virtual ~DynamicBridge() {}
+ virtual void propagateBinding(const std::string& key, const std::string& tagList, const std::string& op, const std::string& origin) = 0;
+ virtual void sendReorigin() = 0;
+ virtual bool containsLocalTag(const std::string& tagList) const = 0;
+ virtual const std::string& getLocalTag() const = 0;
+ };
+
+ void registerDynamicBridge(DynamicBridge* db);
+ void removeDynamicBridge(DynamicBridge* db);
+ virtual bool supportsDynamicBinding() { return false; }
+
+protected:
+ qpid::sys::Mutex bridgeLock;
+ std::vector<DynamicBridge*> bridgeVector;
+
+ virtual void handleHelloRequest();
+ void propagateFedOp(const std::string& routingKey, const std::string& tags,
+ const std::string& op, const std::string& origin);
+};
+
+}}
+
+#endif /*!_broker_Exchange.cpp_h*/
diff --git a/RC9/qpid/cpp/src/qpid/broker/ExchangeRegistry.cpp b/RC9/qpid/cpp/src/qpid/broker/ExchangeRegistry.cpp
new file mode 100644
index 0000000000..01f8bbfee6
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/ExchangeRegistry.cpp
@@ -0,0 +1,109 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "ExchangeRegistry.h"
+#include "DirectExchange.h"
+#include "FanOutExchange.h"
+#include "HeadersExchange.h"
+#include "TopicExchange.h"
+#include "qpid/management/ManagementExchange.h"
+#include "qpid/framing/reply_exceptions.h"
+
+using namespace qpid::broker;
+using namespace qpid::sys;
+using std::pair;
+using qpid::framing::FieldTable;
+
+pair<Exchange::shared_ptr, bool> ExchangeRegistry::declare(const string& name, const string& type)
+ throw(UnknownExchangeTypeException){
+
+ return declare(name, type, false, FieldTable());
+}
+
+pair<Exchange::shared_ptr, bool> ExchangeRegistry::declare(const string& name, const string& type,
+ bool durable, const FieldTable& args)
+ throw(UnknownExchangeTypeException){
+ RWlock::ScopedWlock locker(lock);
+ ExchangeMap::iterator i = exchanges.find(name);
+ if (i == exchanges.end()) {
+ Exchange::shared_ptr exchange;
+
+ if(type == TopicExchange::typeName){
+ exchange = Exchange::shared_ptr(new TopicExchange(name, durable, args, parent));
+ }else if(type == DirectExchange::typeName){
+ exchange = Exchange::shared_ptr(new DirectExchange(name, durable, args, parent));
+ }else if(type == FanOutExchange::typeName){
+ exchange = Exchange::shared_ptr(new FanOutExchange(name, durable, args, parent));
+ }else if (type == HeadersExchange::typeName) {
+ exchange = Exchange::shared_ptr(new HeadersExchange(name, durable, args, parent));
+ }else if (type == ManagementExchange::typeName) {
+ exchange = Exchange::shared_ptr(new ManagementExchange(name, durable, args, parent));
+ }
+ else{
+ FunctionMap::iterator i = factory.find(type);
+ if (i == factory.end()) {
+ throw UnknownExchangeTypeException();
+ } else {
+ exchange = i->second(name, durable, args, parent);
+ }
+ }
+ exchanges[name] = exchange;
+ return std::pair<Exchange::shared_ptr, bool>(exchange, true);
+ } else {
+ return std::pair<Exchange::shared_ptr, bool>(i->second, false);
+ }
+}
+
+void ExchangeRegistry::destroy(const string& name){
+ RWlock::ScopedWlock locker(lock);
+ ExchangeMap::iterator i = exchanges.find(name);
+ if (i != exchanges.end()) {
+ exchanges.erase(i);
+ }
+}
+
+Exchange::shared_ptr ExchangeRegistry::get(const string& name){
+ RWlock::ScopedRlock locker(lock);
+ ExchangeMap::iterator i = exchanges.find(name);
+ if (i == exchanges.end())
+ throw framing::NotFoundException(QPID_MSG("Exchange not found: " << name));
+ return i->second;
+}
+
+bool ExchangeRegistry::registerExchange(const Exchange::shared_ptr& ex) {
+ return exchanges.insert(ExchangeMap::value_type(ex->getName(), ex)).second;
+}
+
+void ExchangeRegistry::registerType(const std::string& type, FactoryFunction f)
+{
+ factory[type] = f;
+}
+
+
+namespace
+{
+const std::string empty;
+}
+
+Exchange::shared_ptr ExchangeRegistry::getDefault()
+{
+ return get(empty);
+}
diff --git a/RC9/qpid/cpp/src/qpid/broker/ExchangeRegistry.h b/RC9/qpid/cpp/src/qpid/broker/ExchangeRegistry.h
new file mode 100644
index 0000000000..787b7896f0
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/ExchangeRegistry.h
@@ -0,0 +1,90 @@
+#ifndef _broker_ExchangeRegistry_h
+#define _broker_ExchangeRegistry_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Exchange.h"
+#include "MessageStore.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/sys/Monitor.h"
+#include "qpid/management/Manageable.h"
+
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+
+#include <algorithm>
+#include <map>
+
+namespace qpid {
+namespace broker {
+
+struct UnknownExchangeTypeException{};
+
+class ExchangeRegistry{
+ public:
+ typedef boost::function4<Exchange::shared_ptr, const std::string&,
+ bool, const qpid::framing::FieldTable&, qpid::management::Manageable*> FactoryFunction;
+
+ ExchangeRegistry () : parent(0) {}
+ std::pair<Exchange::shared_ptr, bool> declare(const std::string& name, const std::string& type)
+ throw(UnknownExchangeTypeException);
+ std::pair<Exchange::shared_ptr, bool> declare(const std::string& name, const std::string& type,
+ bool durable, const qpid::framing::FieldTable& args = framing::FieldTable())
+ throw(UnknownExchangeTypeException);
+ void destroy(const std::string& name);
+ Exchange::shared_ptr get(const std::string& name);
+ Exchange::shared_ptr getDefault();
+
+ /**
+ * Register the manageable parent for declared exchanges
+ */
+ void setParent (management::Manageable* _parent) { parent = _parent; }
+
+ /** Register an exchange instance.
+ *@return true if registered, false if exchange with same name is already registered.
+ */
+ bool registerExchange(const Exchange::shared_ptr&);
+
+ void registerType(const std::string& type, FactoryFunction);
+
+ /** Call f for each exchange in the registry. */
+ template <class F> void eachExchange(F f) const {
+ qpid::sys::RWlock::ScopedWlock l(lock);
+ for (ExchangeMap::const_iterator i = exchanges.begin(); i != exchanges.end(); ++i)
+ f(i->second);
+ }
+
+ private:
+ typedef std::map<std::string, Exchange::shared_ptr> ExchangeMap;
+ typedef std::map<std::string, FactoryFunction > FunctionMap;
+
+ ExchangeMap exchanges;
+ FunctionMap factory;
+ mutable qpid::sys::RWlock lock;
+ management::Manageable* parent;
+
+};
+
+}} // namespace qpid::broker
+
+
+#endif /*!_broker_ExchangeRegistry_h*/
diff --git a/RC9/qpid/cpp/src/qpid/broker/FanOutExchange.cpp b/RC9/qpid/cpp/src/qpid/broker/FanOutExchange.cpp
new file mode 100644
index 0000000000..aa1f7ff30a
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/FanOutExchange.cpp
@@ -0,0 +1,148 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "FanOutExchange.h"
+#include <algorithm>
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::sys;
+namespace _qmf = qmf::org::apache::qpid::broker;
+
+namespace
+{
+const std::string qpidFedOp("qpid.fed.op");
+const std::string qpidFedTags("qpid.fed.tags");
+const std::string qpidFedOrigin("qpid.fed.origin");
+
+const std::string fedOpBind("B");
+const std::string fedOpUnbind("U");
+const std::string fedOpReorigin("R");
+const std::string fedOpHello("H");
+}
+
+FanOutExchange::FanOutExchange(const std::string& _name, Manageable* _parent) :
+ Exchange(_name, _parent)
+{
+ if (mgmtExchange != 0)
+ mgmtExchange->set_type (typeName);
+}
+
+FanOutExchange::FanOutExchange(const std::string& _name, bool _durable,
+ const FieldTable& _args, Manageable* _parent) :
+ Exchange(_name, _durable, _args, _parent)
+{
+ if (mgmtExchange != 0)
+ mgmtExchange->set_type (typeName);
+}
+
+bool FanOutExchange::bind(Queue::shared_ptr queue, const string& /*key*/, const FieldTable* args)
+{
+ string fedOp(args ? args->getAsString(qpidFedOp) : fedOpBind);
+ string fedTags(args ? args->getAsString(qpidFedTags) : "");
+ string fedOrigin(args ? args->getAsString(qpidFedOrigin) : "");
+ bool propagate = false;
+
+ if (args == 0 || fedOp.empty() || fedOp == fedOpBind) {
+ Binding::shared_ptr binding (new Binding ("", queue, this, FieldTable(), fedOrigin));
+ if (bindings.add_unless(binding, MatchQueue(queue))) {
+ propagate = fedBinding.addOrigin(fedOrigin);
+ if (mgmtExchange != 0) {
+ mgmtExchange->inc_bindingCount();
+ ((_qmf::Queue*) queue->GetManagementObject())->inc_bindingCount();
+ }
+ } else {
+ return false;
+ }
+ } else if (fedOp == fedOpUnbind) {
+ propagate = fedBinding.delOrigin(fedOrigin);
+ if (fedBinding.count() == 0)
+ unbind(queue, "", 0);
+ } else if (fedOp == fedOpReorigin) {
+ if (fedBinding.hasLocal()) {
+ propagateFedOp(string(), string(), fedOpBind, string());
+ }
+ }
+
+ routeIVE();
+ if (propagate)
+ propagateFedOp(string(), fedTags, fedOp, fedOrigin);
+ return true;
+}
+
+bool FanOutExchange::unbind(Queue::shared_ptr queue, const string& /*key*/, const FieldTable* /*args*/)
+{
+ bool propagate = false;
+
+ if (bindings.remove_if(MatchQueue(queue))) {
+ propagate = fedBinding.delOrigin();
+ if (mgmtExchange != 0) {
+ mgmtExchange->dec_bindingCount();
+ ((_qmf::Queue*) queue->GetManagementObject())->dec_bindingCount();
+ }
+ } else {
+ return false;
+ }
+
+ if (propagate)
+ propagateFedOp(string(), string(), fedOpUnbind, string());
+ return true;
+}
+
+void FanOutExchange::route(Deliverable& msg, const string& /*routingKey*/, const FieldTable* /*args*/){
+ PreRoute pr(msg, this);
+ uint32_t count(0);
+
+ BindingsArray::ConstPtr p = bindings.snapshot();
+ if (p.get()){
+ for(std::vector<Binding::shared_ptr>::const_iterator i = p->begin(); i != p->end(); ++i, count++){
+ msg.deliverTo((*i)->queue);
+ if ((*i)->mgmtBinding != 0)
+ (*i)->mgmtBinding->inc_msgMatched ();
+ }
+ }
+
+ if (mgmtExchange != 0)
+ {
+ mgmtExchange->inc_msgReceives ();
+ mgmtExchange->inc_byteReceives (msg.contentSize ());
+ if (count == 0)
+ {
+ mgmtExchange->inc_msgDrops ();
+ mgmtExchange->inc_byteDrops (msg.contentSize ());
+ }
+ else
+ {
+ mgmtExchange->inc_msgRoutes (count);
+ mgmtExchange->inc_byteRoutes (count * msg.contentSize ());
+ }
+ }
+}
+
+bool FanOutExchange::isBound(Queue::shared_ptr queue, const string* const, const FieldTable* const)
+{
+ BindingsArray::ConstPtr ptr = bindings.snapshot();
+ return ptr && std::find_if(ptr->begin(), ptr->end(), MatchQueue(queue)) != ptr->end();
+}
+
+
+FanOutExchange::~FanOutExchange() {}
+
+const std::string FanOutExchange::typeName("fanout");
diff --git a/RC9/qpid/cpp/src/qpid/broker/FanOutExchange.h b/RC9/qpid/cpp/src/qpid/broker/FanOutExchange.h
new file mode 100644
index 0000000000..5884a19732
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/FanOutExchange.h
@@ -0,0 +1,65 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _FanOutExchange_
+#define _FanOutExchange_
+
+#include <map>
+#include <vector>
+#include "Exchange.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/sys/CopyOnWriteArray.h"
+#include "Queue.h"
+
+namespace qpid {
+namespace broker {
+
+class FanOutExchange : public virtual Exchange {
+ typedef qpid::sys::CopyOnWriteArray<Binding::shared_ptr> BindingsArray;
+ BindingsArray bindings;
+ FedBinding fedBinding;
+ public:
+ static const std::string typeName;
+
+ FanOutExchange(const std::string& name, management::Manageable* parent = 0);
+ FanOutExchange(const string& _name, bool _durable,
+ const qpid::framing::FieldTable& _args,
+ management::Manageable* parent = 0);
+
+ virtual std::string getType() const { return typeName; }
+
+ virtual bool bind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args);
+
+ virtual bool unbind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args);
+
+ virtual void route(Deliverable& msg, const std::string& routingKey, const qpid::framing::FieldTable* args);
+
+ virtual bool isBound(Queue::shared_ptr queue, const string* const routingKey, const qpid::framing::FieldTable* const args);
+
+ virtual ~FanOutExchange();
+ virtual bool supportsDynamicBinding() { return true; }
+};
+
+}
+}
+
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/HandlerImpl.h b/RC9/qpid/cpp/src/qpid/broker/HandlerImpl.h
new file mode 100644
index 0000000000..4c51e2a826
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/HandlerImpl.h
@@ -0,0 +1,53 @@
+#ifndef _broker_HandlerImpl_h
+#define _broker_HandlerImpl_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "SemanticState.h"
+#include "SessionContext.h"
+#include "ConnectionState.h"
+
+namespace qpid {
+namespace broker {
+
+class Broker;
+
+/**
+ * Base template for protocol handler implementations.
+ * Provides convenience methods for getting common session objects.
+ */
+class HandlerImpl {
+ protected:
+ SemanticState& state;
+ SessionContext& session;
+
+ HandlerImpl(SemanticState& s) : state(s), session(s.getSession()) {}
+
+ framing::AMQP_ClientProxy& getProxy() { return session.getProxy(); }
+ ConnectionState& getConnection() { return session.getConnection(); }
+ Broker& getBroker() { return session.getConnection().getBroker(); }
+};
+
+}} // namespace qpid::broker
+
+
+
+#endif /*!_broker_HandlerImpl_h*/
+
+
diff --git a/RC9/qpid/cpp/src/qpid/broker/HeadersExchange.cpp b/RC9/qpid/cpp/src/qpid/broker/HeadersExchange.cpp
new file mode 100644
index 0000000000..104b34da8b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/HeadersExchange.cpp
@@ -0,0 +1,226 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "HeadersExchange.h"
+#include "qpid/framing/FieldValue.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/log/Statement.h"
+#include <algorithm>
+
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::sys;
+namespace _qmf = qmf::org::apache::qpid::broker;
+
+// TODO aconway 2006-09-20: More efficient matching algorithm.
+// The current search algorithm really sucks.
+// Fieldtables are heavy, maybe use shared_ptr to do handle-body.
+
+using namespace qpid::broker;
+
+namespace {
+ const std::string all("all");
+ const std::string any("any");
+ const std::string x_match("x-match");
+ const std::string empty;
+}
+
+HeadersExchange::HeadersExchange(const string& _name, Manageable* _parent) :
+ Exchange(_name, _parent)
+{
+ if (mgmtExchange != 0)
+ mgmtExchange->set_type (typeName);
+}
+
+HeadersExchange::HeadersExchange(const std::string& _name, bool _durable,
+ const FieldTable& _args, Manageable* _parent) :
+ Exchange(_name, _durable, _args, _parent)
+{
+ if (mgmtExchange != 0)
+ mgmtExchange->set_type (typeName);
+}
+
+std::string HeadersExchange::getMatch(const FieldTable* args)
+{
+ if (!args) {
+ throw InternalErrorException(QPID_MSG("No arguments given."));
+ }
+ FieldTable::ValuePtr what = args->get(x_match);
+ if (!what) {
+ return empty;
+ }
+ if (!what->convertsTo<std::string>()) {
+ throw InternalErrorException(QPID_MSG("Invalid x-match value binding to headers exchange."));
+ }
+ return what->get<std::string>();
+}
+
+bool HeadersExchange::bind(Queue::shared_ptr queue, const string& bindingKey, const FieldTable* args){
+ std::string what = getMatch(args);
+ if (what != all && what != any)
+ throw InternalErrorException(QPID_MSG("Invalid x-match value binding to headers exchange."));
+
+ Binding::shared_ptr binding (new Binding (bindingKey, queue, this, *args));
+ if (bindings.add_unless(binding, MatchArgs(queue, args))) {
+ if (mgmtExchange != 0) {
+ mgmtExchange->inc_bindingCount();
+ ((_qmf::Queue*) queue->GetManagementObject())->inc_bindingCount();
+ }
+ routeIVE();
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool HeadersExchange::unbind(Queue::shared_ptr queue, const string& bindingKey, const FieldTable*){
+ if (bindings.remove_if(MatchKey(queue, bindingKey))) {
+ if (mgmtExchange != 0) {
+ mgmtExchange->dec_bindingCount();
+ ((_qmf::Queue*) queue->GetManagementObject())->dec_bindingCount();
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+void HeadersExchange::route(Deliverable& msg, const string& /*routingKey*/, const FieldTable* args){
+ if (!args) return;//can't match if there were no headers passed in
+ PreRoute pr(msg, this);
+
+ uint32_t count(0);
+
+ Bindings::ConstPtr p = bindings.snapshot();
+ if (p.get()){
+ for (std::vector<Binding::shared_ptr>::const_iterator i = p->begin(); i != p->end(); ++i, count++) {
+ if (match((*i)->args, *args)) msg.deliverTo((*i)->queue);
+ if ((*i)->mgmtBinding != 0)
+ (*i)->mgmtBinding->inc_msgMatched ();
+ }
+ }
+
+ if (mgmtExchange != 0)
+ {
+ mgmtExchange->inc_msgReceives ();
+ mgmtExchange->inc_byteReceives (msg.contentSize ());
+ if (count == 0)
+ {
+ mgmtExchange->inc_msgDrops ();
+ mgmtExchange->inc_byteDrops (msg.contentSize ());
+ }
+ else
+ {
+ mgmtExchange->inc_msgRoutes (count);
+ mgmtExchange->inc_byteRoutes (count * msg.contentSize ());
+ }
+ }
+}
+
+
+bool HeadersExchange::isBound(Queue::shared_ptr queue, const string* const, const FieldTable* const args)
+{
+ Bindings::ConstPtr p = bindings.snapshot();
+ if (p.get()){
+ for (std::vector<Binding::shared_ptr>::const_iterator i = p->begin(); i != p->end(); ++i) {
+ if ( (!args || equal((*i)->args, *args)) && (!queue || (*i)->queue == queue)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+HeadersExchange::~HeadersExchange() {}
+
+const std::string HeadersExchange::typeName("headers");
+
+namespace
+{
+
+ bool match_values(const FieldValue& bind, const FieldValue& msg) {
+ return bind.empty() || bind == msg;
+ }
+
+}
+
+
+bool HeadersExchange::match(const FieldTable& bind, const FieldTable& msg) {
+ typedef FieldTable::ValueMap Map;
+ std::string what = getMatch(&bind);
+ if (what == all) {
+ for (Map::const_iterator i = bind.begin();
+ i != bind.end();
+ ++i)
+ {
+ if (i->first != x_match)
+ {
+ Map::const_iterator j = msg.find(i->first);
+ if (j == msg.end()) return false;
+ if (!match_values(*(i->second), *(j->second))) return false;
+ }
+ }
+ return true;
+ } else if (what == any) {
+ for (Map::const_iterator i = bind.begin();
+ i != bind.end();
+ ++i)
+ {
+ if (i->first != x_match)
+ {
+ Map::const_iterator j = msg.find(i->first);
+ if (j != msg.end()) {
+ if (match_values(*(i->second), *(j->second))) return true;
+ }
+ }
+ }
+ return false;
+ } else {
+ return false;
+ }
+}
+
+bool HeadersExchange::equal(const FieldTable& a, const FieldTable& b) {
+ typedef FieldTable::ValueMap Map;
+ for (Map::const_iterator i = a.begin();
+ i != a.end();
+ ++i)
+ {
+ Map::const_iterator j = b.find(i->first);
+ if (j == b.end()) return false;
+ if (!match_values(*(i->second), *(j->second))) return false;
+ }
+ return true;
+}
+
+HeadersExchange::MatchArgs::MatchArgs(Queue::shared_ptr q, const qpid::framing::FieldTable* a) : queue(q), args(a) {}
+bool HeadersExchange::MatchArgs::operator()(Exchange::Binding::shared_ptr b)
+{
+ return b->queue == queue && b->args == *args;
+}
+
+HeadersExchange::MatchKey::MatchKey(Queue::shared_ptr q, const std::string& k) : queue(q), key(k) {}
+
+bool HeadersExchange::MatchKey::operator()(Exchange::Binding::shared_ptr b)
+{
+ return b->queue == queue && b->key == key;
+}
diff --git a/RC9/qpid/cpp/src/qpid/broker/HeadersExchange.h b/RC9/qpid/cpp/src/qpid/broker/HeadersExchange.h
new file mode 100644
index 0000000000..e10fab2250
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/HeadersExchange.h
@@ -0,0 +1,88 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _HeadersExchange_
+#define _HeadersExchange_
+
+#include <vector>
+#include "Exchange.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/sys/CopyOnWriteArray.h"
+#include "qpid/sys/Mutex.h"
+#include "Queue.h"
+
+namespace qpid {
+namespace broker {
+
+
+class HeadersExchange : public virtual Exchange {
+ typedef std::pair<qpid::framing::FieldTable, Binding::shared_ptr> HeaderMap;
+ typedef qpid::sys::CopyOnWriteArray<Binding::shared_ptr> Bindings;
+
+ struct MatchArgs
+ {
+ const Queue::shared_ptr queue;
+ const qpid::framing::FieldTable* args;
+ MatchArgs(Queue::shared_ptr q, const qpid::framing::FieldTable* a);
+ bool operator()(Exchange::Binding::shared_ptr b);
+ };
+ struct MatchKey
+ {
+ const Queue::shared_ptr queue;
+ const std::string& key;
+ MatchKey(Queue::shared_ptr q, const std::string& k);
+ bool operator()(Exchange::Binding::shared_ptr b);
+ };
+
+ Bindings bindings;
+ qpid::sys::Mutex lock;
+
+ static std::string getMatch(const framing::FieldTable* args);
+
+ public:
+ static const std::string typeName;
+
+ HeadersExchange(const string& name, management::Manageable* parent = 0);
+ HeadersExchange(const string& _name, bool _durable,
+ const qpid::framing::FieldTable& _args,
+ management::Manageable* parent = 0);
+
+ virtual std::string getType() const { return typeName; }
+
+ virtual bool bind(Queue::shared_ptr queue, const string& routingKey, const qpid::framing::FieldTable* args);
+
+ virtual bool unbind(Queue::shared_ptr queue, const string& routingKey, const qpid::framing::FieldTable* args);
+
+ virtual void route(Deliverable& msg, const string& routingKey, const qpid::framing::FieldTable* args);
+
+ virtual bool isBound(Queue::shared_ptr queue, const string* const routingKey, const qpid::framing::FieldTable* const args);
+
+ virtual ~HeadersExchange();
+
+ static bool match(const qpid::framing::FieldTable& bindArgs, const qpid::framing::FieldTable& msgArgs);
+ static bool equal(const qpid::framing::FieldTable& bindArgs, const qpid::framing::FieldTable& msgArgs);
+};
+
+
+
+}
+}
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/IncompleteMessageList.cpp b/RC9/qpid/cpp/src/qpid/broker/IncompleteMessageList.cpp
new file mode 100644
index 0000000000..2077e633ec
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/IncompleteMessageList.cpp
@@ -0,0 +1,81 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "IncompleteMessageList.h"
+
+namespace qpid {
+namespace broker {
+
+IncompleteMessageList::IncompleteMessageList() :
+ callback(boost::bind(&IncompleteMessageList::enqueueComplete, this, _1))
+{}
+
+IncompleteMessageList::~IncompleteMessageList()
+{
+ sys::Mutex::ScopedLock l(lock);
+ std::for_each(incomplete.begin(), incomplete.end(), boost::bind(&Message::resetEnqueueCompleteCallback, _1));
+}
+
+void IncompleteMessageList::add(boost::intrusive_ptr<Message> msg)
+{
+ sys::Mutex::ScopedLock l(lock);
+ msg->setEnqueueCompleteCallback(callback);
+ incomplete.push_back(msg);
+}
+
+void IncompleteMessageList::enqueueComplete(const boost::intrusive_ptr<Message>& ) {
+ sys::Mutex::ScopedLock l(lock);
+ lock.notify();
+}
+
+void IncompleteMessageList::process(const CompletionListener& listen, bool sync)
+{
+ sys::Mutex::ScopedLock l(lock);
+ while (!incomplete.empty()) {
+ boost::intrusive_ptr<Message>& msg = incomplete.front();
+ if (!msg->isEnqueueComplete()) {
+ if (sync){
+ {
+ sys::Mutex::ScopedUnlock u(lock);
+ msg->flush(); // Can re-enter IncompleteMessageList::enqueueComplete
+ }
+ while (!msg->isEnqueueComplete())
+ lock.wait();
+ } else {
+ //leave the message as incomplete for now
+ return;
+ }
+ }
+ listen(msg);
+ incomplete.pop_front();
+ }
+}
+
+void IncompleteMessageList::each(const CompletionListener& listen) {
+ Messages snapshot;
+ {
+ sys::Mutex::ScopedLock l(lock);
+ snapshot = incomplete;
+ }
+ std::for_each(incomplete.begin(), incomplete.end(), listen); // FIXME aconway 2008-11-07: passed by ref or value?
+}
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/broker/IncompleteMessageList.h b/RC9/qpid/cpp/src/qpid/broker/IncompleteMessageList.h
new file mode 100644
index 0000000000..f89c0023b0
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/IncompleteMessageList.h
@@ -0,0 +1,57 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _IncompleteMessageList_
+#define _IncompleteMessageList_
+
+#include "qpid/sys/Monitor.h"
+#include "qpid/broker/Message.h"
+#include <boost/intrusive_ptr.hpp>
+#include <boost/function.hpp>
+#include <list>
+
+namespace qpid {
+namespace broker {
+
+class IncompleteMessageList
+{
+ typedef std::list< boost::intrusive_ptr<Message> > Messages;
+
+ void enqueueComplete(const boost::intrusive_ptr<Message>&);
+
+ sys::Monitor lock;
+ Messages incomplete;
+ Message::MessageCallback callback;
+
+public:
+ typedef Message::MessageCallback CompletionListener;
+
+ IncompleteMessageList();
+ ~IncompleteMessageList();
+
+ void add(boost::intrusive_ptr<Message> msg);
+ void process(const CompletionListener& l, bool sync);
+ void each(const CompletionListener& l);
+};
+
+
+}}
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/Link.cpp b/RC9/qpid/cpp/src/qpid/broker/Link.cpp
new file mode 100644
index 0000000000..bda9c80f0b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/Link.cpp
@@ -0,0 +1,398 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Link.h"
+#include "LinkRegistry.h"
+#include "Broker.h"
+#include "Connection.h"
+#include "qmf/org/apache/qpid/broker/EventBrokerLinkUp.h"
+#include "qmf/org/apache/qpid/broker/EventBrokerLinkDown.h"
+#include "boost/bind.hpp"
+#include "qpid/log/Statement.h"
+#include "qpid/framing/enum.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "AclModule.h"
+
+using namespace qpid::broker;
+using qpid::framing::Buffer;
+using qpid::framing::FieldTable;
+using qpid::framing::NotAllowedException;
+using qpid::framing::connection::CLOSE_CODE_CONNECTION_FORCED;
+using qpid::management::ManagementAgent;
+using qpid::management::ManagementObject;
+using qpid::management::Manageable;
+using qpid::management::Args;
+using qpid::sys::Mutex;
+using std::stringstream;
+namespace _qmf = qmf::org::apache::qpid::broker;
+
+Link::Link(LinkRegistry* _links,
+ MessageStore* _store,
+ string& _host,
+ uint16_t _port,
+ string& _transport,
+ bool _durable,
+ string& _authMechanism,
+ string& _username,
+ string& _password,
+ Broker* _broker,
+ Manageable* parent)
+ : links(_links), store(_store), host(_host), port(_port),
+ transport(_transport),
+ durable(_durable),
+ authMechanism(_authMechanism), username(_username), password(_password),
+ persistenceId(0), mgmtObject(0), broker(_broker), state(0),
+ visitCount(0),
+ currentInterval(1),
+ closing(false),
+ channelCounter(1),
+ connection(0),
+ agent(0)
+{
+ if (parent != 0)
+ {
+ agent = ManagementAgent::Singleton::getInstance();
+ if (agent != 0)
+ {
+ mgmtObject = new _qmf::Link(agent, this, parent, _host, _port, _transport, _durable);
+ if (!durable)
+ agent->addObject(mgmtObject);
+ }
+ }
+ setStateLH(STATE_WAITING);
+}
+
+Link::~Link ()
+{
+ if (state == STATE_OPERATIONAL && connection != 0)
+ connection->close(CLOSE_CODE_CONNECTION_FORCED, "closed by management");
+
+ if (mgmtObject != 0)
+ mgmtObject->resourceDestroy ();
+}
+
+void Link::setStateLH (int newState)
+{
+ if (newState == state)
+ return;
+
+ state = newState;
+ if (mgmtObject == 0)
+ return;
+
+ switch (state)
+ {
+ case STATE_WAITING : mgmtObject->set_state("Waiting"); break;
+ case STATE_CONNECTING : mgmtObject->set_state("Connecting"); break;
+ case STATE_OPERATIONAL : mgmtObject->set_state("Operational"); break;
+ case STATE_FAILED : mgmtObject->set_state("Failed"); break;
+ case STATE_CLOSED : mgmtObject->set_state("Closed"); break;
+ }
+}
+
+void Link::startConnectionLH ()
+{
+ try {
+ // Set the state before calling connect. It is possible that connect
+ // will fail synchronously and call Link::closed before returning.
+ setStateLH(STATE_CONNECTING);
+ broker->connect (host, port, transport,
+ boost::bind (&Link::closed, this, _1, _2));
+ } catch(std::exception& e) {
+ setStateLH(STATE_WAITING);
+ if (mgmtObject != 0)
+ mgmtObject->set_lastError (e.what());
+ }
+}
+
+void Link::established ()
+{
+ Mutex::ScopedLock mutex(lock);
+ stringstream addr;
+ addr << host << ":" << port;
+
+ QPID_LOG (info, "Inter-broker link established to " << addr.str());
+ agent->raiseEvent(_qmf::EventBrokerLinkUp(addr.str()));
+ setStateLH(STATE_OPERATIONAL);
+ currentInterval = 1;
+ visitCount = 0;
+ if (closing)
+ destroy();
+}
+
+void Link::closed (int, std::string text)
+{
+ Mutex::ScopedLock mutex(lock);
+
+ connection = 0;
+
+ if (state == STATE_OPERATIONAL) {
+ stringstream addr;
+ addr << host << ":" << port;
+ QPID_LOG (warning, "Inter-broker link disconnected from " << addr.str());
+ agent->raiseEvent(_qmf::EventBrokerLinkDown(addr.str()));
+ }
+
+ for (Bridges::iterator i = active.begin(); i != active.end(); i++) {
+ (*i)->cancel();
+ created.push_back(*i);
+ }
+ active.clear();
+
+ if (state != STATE_FAILED)
+ {
+ setStateLH(STATE_WAITING);
+ if (mgmtObject != 0)
+ mgmtObject->set_lastError (text);
+ }
+
+ if (closing)
+ destroy();
+}
+
+void Link::destroy ()
+{
+ {
+ Mutex::ScopedLock mutex(lock);
+ Bridges toDelete;
+
+ AclModule* acl = getBroker()->getAcl();
+ std::string userID = getUsername() + "@" + getBroker()->getOptions().realm;
+ if (acl && !acl->authorise(userID,acl::ACT_DELETE,acl::OBJ_LINK,"")){
+ throw NotAllowedException("ACL denied delete link request");
+ }
+
+ QPID_LOG (info, "Inter-broker link to " << host << ":" << port << " removed by management");
+ if (connection)
+ connection->close(CLOSE_CODE_CONNECTION_FORCED, "closed by management");
+
+ setStateLH(STATE_CLOSED);
+
+ // Move the bridges to be deleted into a local vector so there is no
+ // corruption of the iterator caused by bridge deletion.
+ for (Bridges::iterator i = active.begin(); i != active.end(); i++)
+ toDelete.push_back(*i);
+ active.clear();
+
+ for (Bridges::iterator i = created.begin(); i != created.end(); i++)
+ toDelete.push_back(*i);
+ created.clear();
+
+ // Now delete all bridges on this link.
+ for (Bridges::iterator i = toDelete.begin(); i != toDelete.end(); i++)
+ (*i)->destroy();
+ toDelete.clear();
+ }
+ links->destroy (host, port);
+}
+
+void Link::add(Bridge::shared_ptr bridge)
+{
+ Mutex::ScopedLock mutex(lock);
+ created.push_back (bridge);
+}
+
+void Link::cancel(Bridge::shared_ptr bridge)
+{
+ Mutex::ScopedLock mutex(lock);
+
+ for (Bridges::iterator i = created.begin(); i != created.end(); i++) {
+ if ((*i).get() == bridge.get()) {
+ created.erase(i);
+ break;
+ }
+ }
+ for (Bridges::iterator i = active.begin(); i != active.end(); i++) {
+ if ((*i).get() == bridge.get()) {
+ bridge->cancel();
+ active.erase(i);
+ break;
+ }
+ }
+}
+
+void Link::ioThreadProcessing()
+{
+ Mutex::ScopedLock mutex(lock);
+
+ if (state != STATE_OPERATIONAL)
+ return;
+
+ //process any pending creates
+ if (!created.empty()) {
+ for (Bridges::iterator i = created.begin(); i != created.end(); ++i) {
+ active.push_back(*i);
+ (*i)->create(*connection);
+ }
+ created.clear();
+ }
+}
+
+void Link::setConnection(Connection* c)
+{
+ Mutex::ScopedLock mutex(lock);
+ connection = c;
+}
+
+void Link::maintenanceVisit ()
+{
+ Mutex::ScopedLock mutex(lock);
+
+ if (state == STATE_WAITING)
+ {
+ visitCount++;
+ if (visitCount >= currentInterval)
+ {
+ visitCount = 0;
+ currentInterval *= 2;
+ if (currentInterval > MAX_INTERVAL)
+ currentInterval = MAX_INTERVAL;
+ startConnectionLH();
+ }
+ }
+ else if (state == STATE_OPERATIONAL && !created.empty() && connection != 0)
+ connection->requestIOProcessing (boost::bind(&Link::ioThreadProcessing, this));
+}
+
+uint Link::nextChannel()
+{
+ Mutex::ScopedLock mutex(lock);
+
+ return channelCounter++;
+}
+
+void Link::notifyConnectionForced(const string text)
+{
+ Mutex::ScopedLock mutex(lock);
+
+ setStateLH(STATE_FAILED);
+ if (mgmtObject != 0)
+ mgmtObject->set_lastError(text);
+}
+
+void Link::setPersistenceId(uint64_t id) const
+{
+ if (mgmtObject != 0 && persistenceId == 0) {
+ ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+ agent->addObject(mgmtObject, id);
+ }
+ persistenceId = id;
+}
+
+const string& Link::getName() const
+{
+ return host;
+}
+
+Link::shared_ptr Link::decode(LinkRegistry& links, Buffer& buffer)
+{
+ string host;
+ uint16_t port;
+ string transport;
+ string authMechanism;
+ string username;
+ string password;
+
+ buffer.getShortString(host);
+ port = buffer.getShort();
+ buffer.getShortString(transport);
+ bool durable(buffer.getOctet());
+ buffer.getShortString(authMechanism);
+ buffer.getShortString(username);
+ buffer.getShortString(password);
+
+ return links.declare(host, port, transport, durable, authMechanism, username, password).first;
+}
+
+void Link::encode(Buffer& buffer) const
+{
+ buffer.putShortString(string("link"));
+ buffer.putShortString(host);
+ buffer.putShort(port);
+ buffer.putShortString(transport);
+ buffer.putOctet(durable ? 1 : 0);
+ buffer.putShortString(authMechanism);
+ buffer.putShortString(username);
+ buffer.putShortString(password);
+}
+
+uint32_t Link::encodedSize() const
+{
+ return host.size() + 1 // short-string (host)
+ + 5 // short-string ("link")
+ + 2 // port
+ + transport.size() + 1 // short-string(transport)
+ + 1 // durable
+ + authMechanism.size() + 1
+ + username.size() + 1
+ + password.size() + 1;
+}
+
+ManagementObject* Link::GetManagementObject (void) const
+{
+ return (ManagementObject*) mgmtObject;
+}
+
+Manageable::status_t Link::ManagementMethod (uint32_t op, Args& args, string& text)
+{
+ switch (op)
+ {
+ case _qmf::Link::METHOD_CLOSE :
+ closing = true;
+ if (state != STATE_CONNECTING)
+ destroy();
+ return Manageable::STATUS_OK;
+
+ case _qmf::Link::METHOD_BRIDGE :
+ _qmf::ArgsLinkBridge& iargs = (_qmf::ArgsLinkBridge&) args;
+
+ // Durable bridges are only valid on durable links
+ if (iargs.i_durable && !durable) {
+ text = "Can't create a durable route on a non-durable link";
+ return Manageable::STATUS_USER;
+ }
+
+ if (iargs.i_dynamic) {
+ Exchange::shared_ptr exchange = getBroker()->getExchanges().get(iargs.i_src);
+ if (exchange.get() == 0) {
+ text = "Exchange not found";
+ return Manageable::STATUS_USER;
+ }
+ if (!exchange->supportsDynamicBinding()) {
+ text = "Exchange type does not support dynamic routing";
+ return Manageable::STATUS_USER;
+ }
+ }
+
+ std::pair<Bridge::shared_ptr, bool> result =
+ links->declare (host, port, iargs.i_durable, iargs.i_src,
+ iargs.i_dest, iargs.i_key, iargs.i_srcIsQueue,
+ iargs.i_srcIsLocal, iargs.i_tag, iargs.i_excludes,
+ iargs.i_dynamic);
+
+ if (result.second && iargs.i_durable)
+ store->create(*result.first);
+
+ return Manageable::STATUS_OK;
+ }
+
+ return Manageable::STATUS_UNKNOWN_METHOD;
+}
diff --git a/RC9/qpid/cpp/src/qpid/broker/Link.h b/RC9/qpid/cpp/src/qpid/broker/Link.h
new file mode 100644
index 0000000000..a8dd528071
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/Link.h
@@ -0,0 +1,136 @@
+#ifndef _broker_Link_h
+#define _broker_Link_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <boost/shared_ptr.hpp>
+#include "MessageStore.h"
+#include "PersistableConfig.h"
+#include "Bridge.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/management/Manageable.h"
+#include "qpid/agent/ManagementAgent.h"
+#include "qmf/org/apache/qpid/broker/Link.h"
+#include <boost/ptr_container/ptr_vector.hpp>
+
+namespace qpid {
+ namespace broker {
+
+ using std::string;
+ class LinkRegistry;
+ class Broker;
+ class Connection;
+
+ class Link : public PersistableConfig, public management::Manageable {
+ private:
+ sys::Mutex lock;
+ LinkRegistry* links;
+ MessageStore* store;
+ string host;
+ uint16_t port;
+ string transport;
+ bool durable;
+ string authMechanism;
+ string username;
+ string password;
+ mutable uint64_t persistenceId;
+ qmf::org::apache::qpid::broker::Link* mgmtObject;
+ Broker* broker;
+ int state;
+ uint32_t visitCount;
+ uint32_t currentInterval;
+ bool closing;
+
+ typedef std::vector<Bridge::shared_ptr> Bridges;
+ Bridges created; // Bridges pending creation
+ Bridges active; // Bridges active
+ uint channelCounter;
+ Connection* connection;
+ management::ManagementAgent* agent;
+
+ static const int STATE_WAITING = 1;
+ static const int STATE_CONNECTING = 2;
+ static const int STATE_OPERATIONAL = 3;
+ static const int STATE_FAILED = 4;
+ static const int STATE_CLOSED = 5;
+
+ static const uint32_t MAX_INTERVAL = 32;
+
+ void setStateLH (int newState);
+ void startConnectionLH(); // Start the IO Connection
+ void destroy(); // Called when mgmt deletes this link
+ void ioThreadProcessing(); // Called on connection's IO thread by request
+
+ public:
+ typedef boost::shared_ptr<Link> shared_ptr;
+
+ Link(LinkRegistry* links,
+ MessageStore* store,
+ string& host,
+ uint16_t port,
+ string& transport,
+ bool durable,
+ string& authMechanism,
+ string& username,
+ string& password,
+ Broker* broker,
+ management::Manageable* parent = 0);
+ virtual ~Link();
+
+ std::string getHost() { return host; }
+ uint16_t getPort() { return port; }
+ bool isDurable() { return durable; }
+ void maintenanceVisit ();
+ uint nextChannel();
+ void add(Bridge::shared_ptr);
+ void cancel(Bridge::shared_ptr);
+
+ void established(); // Called when connection is created
+ void closed(int, std::string); // Called when connection goes away
+ void setConnection(Connection*); // Set pointer to the AMQP Connection
+
+ string getAuthMechanism() { return authMechanism; }
+ string getUsername() { return username; }
+ string getPassword() { return password; }
+ Broker* getBroker() { return broker; }
+
+ void notifyConnectionForced(const std::string text);
+
+ // PersistableConfig:
+ void setPersistenceId(uint64_t id) const;
+ uint64_t getPersistenceId() const { return persistenceId; }
+ uint32_t encodedSize() const;
+ void encode(framing::Buffer& buffer) const;
+ const string& getName() const;
+
+ static Link::shared_ptr decode(LinkRegistry& links, framing::Buffer& buffer);
+
+ // Manageable entry points
+ management::ManagementObject* GetManagementObject(void) const;
+ management::Manageable::status_t ManagementMethod(uint32_t, management::Args&, std::string&);
+ };
+ }
+}
+
+
+#endif /*!_broker_Link.cpp_h*/
diff --git a/RC9/qpid/cpp/src/qpid/broker/LinkRegistry.cpp b/RC9/qpid/cpp/src/qpid/broker/LinkRegistry.cpp
new file mode 100644
index 0000000000..960e9f21ba
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/LinkRegistry.cpp
@@ -0,0 +1,252 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "LinkRegistry.h"
+#include <iostream>
+
+using namespace qpid::broker;
+using namespace qpid::sys;
+using std::pair;
+using std::stringstream;
+using boost::intrusive_ptr;
+namespace _qmf = qmf::org::apache::qpid::broker;
+
+#define LINK_MAINT_INTERVAL 2
+
+LinkRegistry::LinkRegistry (Broker* _broker) : broker(_broker), parent(0), store(0)
+{
+ timer.add (intrusive_ptr<TimerTask> (new Periodic(*this)));
+}
+
+LinkRegistry::Periodic::Periodic (LinkRegistry& _links) :
+ TimerTask (Duration (LINK_MAINT_INTERVAL * TIME_SEC)), links(_links) {}
+
+void LinkRegistry::Periodic::fire ()
+{
+ links.periodicMaintenance ();
+ links.timer.add (intrusive_ptr<TimerTask> (new Periodic(links)));
+}
+
+void LinkRegistry::periodicMaintenance ()
+{
+ Mutex::ScopedLock locker(lock);
+
+ linksToDestroy.clear();
+ bridgesToDestroy.clear();
+ for (LinkMap::iterator i = links.begin(); i != links.end(); i++)
+ i->second->maintenanceVisit();
+}
+
+pair<Link::shared_ptr, bool> LinkRegistry::declare(string& host,
+ uint16_t port,
+ string& transport,
+ bool durable,
+ string& authMechanism,
+ string& username,
+ string& password)
+
+{
+ Mutex::ScopedLock locker(lock);
+ stringstream keystream;
+ keystream << host << ":" << port;
+ string key = string(keystream.str());
+
+ LinkMap::iterator i = links.find(key);
+ if (i == links.end())
+ {
+ Link::shared_ptr link;
+
+ link = Link::shared_ptr (new Link (this, store, host, port, transport, durable,
+ authMechanism, username, password,
+ broker, parent));
+ links[key] = link;
+ return std::pair<Link::shared_ptr, bool>(link, true);
+ }
+ return std::pair<Link::shared_ptr, bool>(i->second, false);
+}
+
+pair<Bridge::shared_ptr, bool> LinkRegistry::declare(std::string& host,
+ uint16_t port,
+ bool durable,
+ std::string& src,
+ std::string& dest,
+ std::string& key,
+ bool isQueue,
+ bool isLocal,
+ std::string& tag,
+ std::string& excludes,
+ bool dynamic)
+{
+ Mutex::ScopedLock locker(lock);
+ stringstream keystream;
+ keystream << host << ":" << port;
+ string linkKey = string(keystream.str());
+
+ keystream << "!" << src << "!" << dest << "!" << key;
+ string bridgeKey = string(keystream.str());
+
+ LinkMap::iterator l = links.find(linkKey);
+ if (l == links.end())
+ return pair<Bridge::shared_ptr, bool>(Bridge::shared_ptr(), false);
+
+ BridgeMap::iterator b = bridges.find(bridgeKey);
+ if (b == bridges.end())
+ {
+ _qmf::ArgsLinkBridge args;
+ Bridge::shared_ptr bridge;
+
+ args.i_durable = durable;
+ args.i_src = src;
+ args.i_dest = dest;
+ args.i_key = key;
+ args.i_srcIsQueue = isQueue;
+ args.i_srcIsLocal = isLocal;
+ args.i_tag = tag;
+ args.i_excludes = excludes;
+ args.i_dynamic = dynamic;
+
+ bridge = Bridge::shared_ptr
+ (new Bridge (l->second.get(), l->second->nextChannel(),
+ boost::bind(&LinkRegistry::destroy, this,
+ host, port, src, dest, key), args));
+ bridges[bridgeKey] = bridge;
+ l->second->add(bridge);
+ return std::pair<Bridge::shared_ptr, bool>(bridge, true);
+ }
+ return std::pair<Bridge::shared_ptr, bool>(b->second, false);
+}
+
+void LinkRegistry::destroy(const string& host, const uint16_t port)
+{
+ Mutex::ScopedLock locker(lock);
+ stringstream keystream;
+ keystream << host << ":" << port;
+ string key = string(keystream.str());
+
+ LinkMap::iterator i = links.find(key);
+ if (i != links.end())
+ {
+ if (i->second->isDurable() && store)
+ store->destroy(*(i->second));
+ linksToDestroy[key] = i->second;
+ links.erase(i);
+ }
+}
+
+void LinkRegistry::destroy(const std::string& host,
+ const uint16_t port,
+ const std::string& src,
+ const std::string& dest,
+ const std::string& key)
+{
+ Mutex::ScopedLock locker(lock);
+ stringstream keystream;
+ keystream << host << ":" << port;
+ string linkKey = string(keystream.str());
+
+ LinkMap::iterator l = links.find(linkKey);
+ if (l == links.end())
+ return;
+
+ keystream << "!" << src << "!" << dest << "!" << key;
+ string bridgeKey = string(keystream.str());
+ BridgeMap::iterator b = bridges.find(bridgeKey);
+ if (b == bridges.end())
+ return;
+
+ l->second->cancel(b->second);
+ if (b->second->isDurable())
+ store->destroy(*(b->second));
+ bridgesToDestroy[bridgeKey] = b->second;
+ bridges.erase(b);
+}
+
+void LinkRegistry::setStore (MessageStore* _store)
+{
+ store = _store;
+}
+
+MessageStore* LinkRegistry::getStore() const {
+ return store;
+}
+
+void LinkRegistry::notifyConnection(const std::string& key, Connection* c)
+{
+ Mutex::ScopedLock locker(lock);
+ LinkMap::iterator l = links.find(key);
+ if (l != links.end())
+ {
+ l->second->established();
+ l->second->setConnection(c);
+ }
+}
+
+void LinkRegistry::notifyClosed(const std::string& key)
+{
+ Mutex::ScopedLock locker(lock);
+ LinkMap::iterator l = links.find(key);
+ if (l != links.end())
+ l->second->closed(0, "Closed by peer");
+}
+
+void LinkRegistry::notifyConnectionForced(const std::string& key, const std::string& text)
+{
+ Mutex::ScopedLock locker(lock);
+ LinkMap::iterator l = links.find(key);
+ if (l != links.end())
+ l->second->notifyConnectionForced(text);
+}
+
+std::string LinkRegistry::getAuthMechanism(const std::string& key)
+{
+ Mutex::ScopedLock locker(lock);
+ LinkMap::iterator l = links.find(key);
+ if (l != links.end())
+ return l->second->getAuthMechanism();
+ return string("ANONYMOUS");
+}
+
+std::string LinkRegistry::getAuthCredentials(const std::string& key)
+{
+ Mutex::ScopedLock locker(lock);
+ LinkMap::iterator l = links.find(key);
+ if (l == links.end())
+ return string();
+
+ string result;
+ result += '\0';
+ result += l->second->getUsername();
+ result += '\0';
+ result += l->second->getPassword();
+
+ return result;
+}
+
+std::string LinkRegistry::getAuthIdentity(const std::string& key)
+{
+ Mutex::ScopedLock locker(lock);
+ LinkMap::iterator l = links.find(key);
+ if (l == links.end())
+ return string();
+
+ return l->second->getUsername();
+}
+
+
diff --git a/RC9/qpid/cpp/src/qpid/broker/LinkRegistry.h b/RC9/qpid/cpp/src/qpid/broker/LinkRegistry.h
new file mode 100644
index 0000000000..d563412cc1
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/LinkRegistry.h
@@ -0,0 +1,123 @@
+#ifndef _broker_LinkRegistry_h
+#define _broker_LinkRegistry_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <map>
+#include "Link.h"
+#include "Bridge.h"
+#include "MessageStore.h"
+#include "Timer.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/management/Manageable.h"
+
+namespace qpid {
+namespace broker {
+
+ class Broker;
+ class Connection;
+ class LinkRegistry {
+
+ // Declare a timer task to manage the establishment of link connections and the
+ // re-establishment of lost link connections.
+ struct Periodic : public TimerTask
+ {
+ LinkRegistry& links;
+
+ Periodic(LinkRegistry& links);
+ virtual ~Periodic() {};
+ void fire();
+ };
+
+ typedef std::map<std::string, Link::shared_ptr> LinkMap;
+ typedef std::map<std::string, Bridge::shared_ptr> BridgeMap;
+
+ LinkMap links;
+ LinkMap linksToDestroy;
+ BridgeMap bridges;
+ BridgeMap bridgesToDestroy;
+
+ qpid::sys::Mutex lock;
+ Broker* broker;
+ Timer timer;
+ management::Manageable* parent;
+ MessageStore* store;
+
+ void periodicMaintenance ();
+
+ public:
+ LinkRegistry (Broker* _broker);
+ std::pair<Link::shared_ptr, bool>
+ declare(std::string& host,
+ uint16_t port,
+ std::string& transport,
+ bool durable,
+ std::string& authMechanism,
+ std::string& username,
+ std::string& password);
+ std::pair<Bridge::shared_ptr, bool>
+ declare(std::string& host,
+ uint16_t port,
+ bool durable,
+ std::string& src,
+ std::string& dest,
+ std::string& key,
+ bool isQueue,
+ bool isLocal,
+ std::string& id,
+ std::string& excludes,
+ bool dynamic);
+
+ void destroy(const std::string& host, const uint16_t port);
+ void destroy(const std::string& host,
+ const uint16_t port,
+ const std::string& src,
+ const std::string& dest,
+ const std::string& key);
+
+ /**
+ * Register the manageable parent for declared queues
+ */
+ void setParent (management::Manageable* _parent) { parent = _parent; }
+
+ /**
+ * Set the store to use. May only be called once.
+ */
+ void setStore (MessageStore*);
+
+ /**
+ * Return the message store used.
+ */
+ MessageStore* getStore() const;
+
+ void notifyConnection (const std::string& key, Connection* c);
+ void notifyClosed (const std::string& key);
+ void notifyConnectionForced (const std::string& key, const std::string& text);
+ std::string getAuthMechanism (const std::string& key);
+ std::string getAuthCredentials (const std::string& key);
+ std::string getAuthIdentity (const std::string& key);
+ };
+}
+}
+
+
+#endif /*!_broker_LinkRegistry_h*/
diff --git a/RC9/qpid/cpp/src/qpid/broker/Message.cpp b/RC9/qpid/cpp/src/qpid/broker/Message.cpp
new file mode 100644
index 0000000000..89f2653a21
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/Message.cpp
@@ -0,0 +1,369 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Message.h"
+#include "ExchangeRegistry.h"
+#include "qpid/StringUtils.h"
+#include "qpid/framing/frame_functors.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/framing/SendContent.h"
+#include "qpid/framing/SequenceNumber.h"
+#include "qpid/framing/TypeFilter.h"
+#include "qpid/log/Statement.h"
+
+#include <time.h>
+
+using boost::intrusive_ptr;
+using qpid::sys::AbsTime;
+using qpid::sys::Duration;
+using qpid::sys::TIME_MSEC;
+using qpid::sys::FAR_FUTURE;
+using std::string;
+using namespace qpid::framing;
+
+namespace qpid {
+namespace broker {
+
+TransferAdapter Message::TRANSFER;
+
+Message::Message(const framing::SequenceNumber& id) :
+ frames(id), persistenceId(0), redelivered(false), loaded(false),
+ staged(false), forcePersistentPolicy(false), publisher(0), adapter(0),
+ expiration(FAR_FUTURE), enqueueCallback(0), dequeueCallback(0) {}
+
+Message::~Message()
+{
+}
+
+void Message::forcePersistent()
+{
+ forcePersistentPolicy = true;
+}
+
+std::string Message::getRoutingKey() const
+{
+ return getAdapter().getRoutingKey(frames);
+}
+
+std::string Message::getExchangeName() const
+{
+ return getAdapter().getExchange(frames);
+}
+
+const boost::shared_ptr<Exchange> Message::getExchange(ExchangeRegistry& registry) const
+{
+ if (!exchange) {
+ exchange = registry.get(getExchangeName());
+ }
+ return exchange;
+}
+
+bool Message::isImmediate() const
+{
+ return getAdapter().isImmediate(frames);
+}
+
+const FieldTable* Message::getApplicationHeaders() const
+{
+ return getAdapter().getApplicationHeaders(frames);
+}
+
+bool Message::isPersistent()
+{
+ return (getAdapter().isPersistent(frames) || forcePersistentPolicy);
+}
+
+bool Message::requiresAccept()
+{
+ return getAdapter().requiresAccept(frames);
+}
+
+uint32_t Message::getRequiredCredit() const
+{
+ //add up payload for all header and content frames in the frameset
+ SumBodySize sum;
+ frames.map_if(sum, TypeFilter2<HEADER_BODY, CONTENT_BODY>());
+ return sum.getSize();
+}
+
+void Message::encode(framing::Buffer& buffer) const
+{
+ //encode method and header frames
+ EncodeFrame f1(buffer);
+ frames.map_if(f1, TypeFilter2<METHOD_BODY, HEADER_BODY>());
+
+ //then encode the payload of each content frame
+ framing::EncodeBody f2(buffer);
+ frames.map_if(f2, TypeFilter<CONTENT_BODY>());
+}
+
+void Message::encodeContent(framing::Buffer& buffer) const
+{
+ //encode the payload of each content frame
+ EncodeBody f2(buffer);
+ frames.map_if(f2, TypeFilter<CONTENT_BODY>());
+}
+
+uint32_t Message::encodedSize() const
+{
+ return encodedHeaderSize() + encodedContentSize();
+}
+
+uint32_t Message::encodedContentSize() const
+{
+ return frames.getContentSize();
+}
+
+uint32_t Message::encodedHeaderSize() const
+{
+ //add up the size for all method and header frames in the frameset
+ SumFrameSize sum;
+ frames.map_if(sum, TypeFilter2<METHOD_BODY, HEADER_BODY>());
+ return sum.getSize();
+}
+
+void Message::decodeHeader(framing::Buffer& buffer)
+{
+ AMQFrame method;
+ method.decode(buffer);
+ frames.append(method);
+
+ AMQFrame header;
+ header.decode(buffer);
+ frames.append(header);
+}
+
+void Message::decodeContent(framing::Buffer& buffer)
+{
+ if (buffer.available()) {
+ //get the data as a string and set that as the content
+ //body on a frame then add that frame to the frameset
+ AMQFrame frame;
+ frame.setBody(AMQContentBody());
+ frame.castBody<AMQContentBody>()->decode(buffer, buffer.available());
+ frames.append(frame);
+ } else {
+ //adjust header flags
+ MarkLastSegment f;
+ frames.map_if(f, TypeFilter<HEADER_BODY>());
+ }
+ //mark content loaded
+ loaded = true;
+}
+
+void Message::releaseContent(MessageStore* _store)
+{
+ if (!store) {
+ store = _store;
+ }
+ if (store) {
+ if (!getPersistenceId()) {
+ intrusive_ptr<PersistableMessage> pmsg(this);
+ store->stage(pmsg);
+ staged = true;
+ }
+ //remove any content frames from the frameset
+ frames.remove(TypeFilter<CONTENT_BODY>());
+ setContentReleased();
+ }
+}
+
+void Message::destroy()
+{
+ if (staged) {
+ if (store) {
+ store->destroy(*this);
+ } else {
+ QPID_LOG(error, "Message content was staged but no store is set so it can't be destroyed");
+ }
+ }
+}
+
+void Message::sendContent(Queue& queue, framing::FrameHandler& out, uint16_t maxFrameSize) const
+{
+ if (isContentReleased()) {
+ //load content from store in chunks of maxContentSize
+ uint16_t maxContentSize = maxFrameSize - AMQFrame::frameOverhead();
+ intrusive_ptr<const PersistableMessage> pmsg(this);
+
+ bool done = false;
+ for (uint64_t offset = 0; !done; offset += maxContentSize)
+ {
+ AMQFrame frame(in_place<AMQContentBody>());
+ string& data = frame.castBody<AMQContentBody>()->getData();
+
+ store->loadContent(queue, pmsg, data, offset, maxContentSize);
+ done = data.size() < maxContentSize;
+ frame.setBof(false);
+ frame.setEof(true);
+ if (offset > 0) {
+ frame.setBos(false);
+ }
+ if (!done) {
+ frame.setEos(false);
+ }
+ QPID_LOG(debug, "loaded frame for delivery: " << frame);
+ out.handle(frame);
+ }
+ } else {
+ Count c;
+ frames.map_if(c, TypeFilter<CONTENT_BODY>());
+
+ SendContent f(out, maxFrameSize, c.getCount());
+ frames.map_if(f, TypeFilter<CONTENT_BODY>());
+ }
+}
+
+void Message::sendHeader(framing::FrameHandler& out, uint16_t /*maxFrameSize*/) const
+{
+ sys::Mutex::ScopedLock l(lock);
+ Relay f(out);
+ frames.map_if(f, TypeFilter<HEADER_BODY>());
+}
+
+// TODO aconway 2007-11-09: Obsolete, remove. Was used to cover over
+// 0-8/0-9 message differences.
+MessageAdapter& Message::getAdapter() const
+{
+ if (!adapter) {
+ if(frames.isA<MessageTransferBody>()) {
+ adapter = &TRANSFER;
+ } else {
+ const AMQMethodBody* method = frames.getMethod();
+ if (!method) throw Exception("Can't adapt message with no method");
+ else throw Exception(QPID_MSG("Can't adapt message based on " << *method));
+ }
+ }
+ return *adapter;
+}
+
+uint64_t Message::contentSize() const
+{
+ return frames.getContentSize();
+}
+
+bool Message::isContentLoaded() const
+{
+ return loaded;
+}
+
+
+namespace
+{
+const std::string X_QPID_TRACE("x-qpid.trace");
+}
+
+bool Message::isExcluded(const std::vector<std::string>& excludes) const
+{
+ const FieldTable* headers = getApplicationHeaders();
+ if (headers) {
+ std::string traceStr = headers->getAsString(X_QPID_TRACE);
+ if (traceStr.size()) {
+ std::vector<std::string> trace = split(traceStr, ", ");
+
+ for (std::vector<std::string>::const_iterator i = excludes.begin(); i != excludes.end(); i++) {
+ for (std::vector<std::string>::const_iterator j = trace.begin(); j != trace.end(); j++) {
+ if (*i == *j) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+void Message::addTraceId(const std::string& id)
+{
+ sys::Mutex::ScopedLock l(lock);
+ if (isA<MessageTransferBody>()) {
+ FieldTable& headers = getProperties<MessageProperties>()->getApplicationHeaders();
+ std::string trace = headers.getAsString(X_QPID_TRACE);
+ if (trace.empty()) {
+ headers.setString(X_QPID_TRACE, id);
+ } else if (trace.find(id) == std::string::npos) {
+ trace += ",";
+ trace += id;
+ headers.setString(X_QPID_TRACE, trace);
+ }
+ }
+}
+
+void Message::setTimestamp()
+{
+ DeliveryProperties* props = getProperties<DeliveryProperties>();
+ //Spec states that timestamp should be set, evaluate the
+ //performance impact before re-enabling this:
+ //time_t now = ::time(0);
+ //props->setTimestamp(now);
+ if (props->getTtl()) {
+ //set expiration (nb: ttl is in millisecs, time_t is in secs)
+ time_t now = ::time(0);
+ props->setExpiration(now + (props->getTtl()/1000));
+ expiration = AbsTime(AbsTime::now(), Duration(props->getTtl() * TIME_MSEC));
+ }
+}
+
+bool Message::hasExpired() const
+{
+ return expiration < FAR_FUTURE && expiration < AbsTime::now();
+}
+
+boost::intrusive_ptr<Message>& Message::getReplacementMessage(const Queue* qfor) const
+{
+ Replacement::iterator i = replacement.find(qfor);
+ if (i != replacement.end()){
+ return i->second;
+ }
+ return empty;
+}
+
+void Message::setReplacementMessage(boost::intrusive_ptr<Message> msg, const Queue* qfor)
+{
+ replacement[qfor] = msg;
+}
+
+void Message::allEnqueuesComplete() {
+ MessageCallback* cb = 0;
+ {
+ sys::Mutex::ScopedLock l(lock);
+ std::swap(cb, enqueueCallback);
+ }
+ if (cb && *cb) (*cb)(intrusive_ptr<Message>(this));
+}
+
+void Message::allDequeuesComplete() {
+ MessageCallback* cb = 0;
+ {
+ sys::Mutex::ScopedLock l(lock);
+ std::swap(cb, dequeueCallback);
+ }
+ if (cb && *cb) (*cb)(intrusive_ptr<Message>(this));
+}
+
+void Message::setEnqueueCompleteCallback(MessageCallback& cb) { enqueueCallback = &cb; }
+void Message::resetEnqueueCompleteCallback() { enqueueCallback = 0; }
+
+void Message::setDequeueCompleteCallback(MessageCallback& cb) { dequeueCallback = &cb; }
+void Message::resetDequeueCompleteCallback() { dequeueCallback = 0; }
+
+}} // namespace qpid::broker
diff --git a/RC9/qpid/cpp/src/qpid/broker/Message.h b/RC9/qpid/cpp/src/qpid/broker/Message.h
new file mode 100644
index 0000000000..bed191fb8d
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/Message.h
@@ -0,0 +1,185 @@
+#ifndef _broker_Message_h
+#define _broker_Message_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "PersistableMessage.h"
+#include "MessageAdapter.h"
+#include "qpid/framing/amqp_types.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Time.h"
+#include "qpid/shared_ptr.h"
+#include <boost/function.hpp>
+#include <string>
+#include <vector>
+
+namespace qpid {
+
+namespace framing {
+class FieldTable;
+class SequenceNumber;
+}
+
+namespace broker {
+class ConnectionToken;
+class Exchange;
+class ExchangeRegistry;
+class MessageStore;
+class Queue;
+
+class Message : public PersistableMessage {
+public:
+ typedef boost::function<void (const boost::intrusive_ptr<Message>&)> MessageCallback;
+
+ Message(const framing::SequenceNumber& id = framing::SequenceNumber());
+ ~Message();
+
+ uint64_t getPersistenceId() const { return persistenceId; }
+ void setPersistenceId(uint64_t _persistenceId) const { persistenceId = _persistenceId; }
+
+ bool getRedelivered() const { return redelivered; }
+ void redeliver() { redelivered = true; }
+
+ const ConnectionToken* getPublisher() const { return publisher; }
+ void setPublisher(ConnectionToken* p) { publisher = p; }
+
+ const framing::SequenceNumber& getCommandId() { return frames.getId(); }
+
+ uint64_t contentSize() const;
+
+ std::string getRoutingKey() const;
+ const boost::shared_ptr<Exchange> getExchange(ExchangeRegistry&) const;
+ std::string getExchangeName() const;
+ bool isImmediate() const;
+ const framing::FieldTable* getApplicationHeaders() const;
+ bool isPersistent();
+ bool requiresAccept();
+ void setTimestamp();
+ bool hasExpired() const;
+
+ framing::FrameSet& getFrames() { return frames; }
+ const framing::FrameSet& getFrames() const { return frames; }
+
+ template <class T> T* getProperties() {
+ qpid::framing::AMQHeaderBody* p = frames.getHeaders();
+ return p->get<T>(true);
+ }
+
+ template <class T> const T* getProperties() const {
+ qpid::framing::AMQHeaderBody* p = frames.getHeaders();
+ return p->get<T>(true);
+ }
+
+ template <class T> const T* hasProperties() const {
+ const qpid::framing::AMQHeaderBody* p = frames.getHeaders();
+ return p->get<T>();
+ }
+
+ template <class T> const T* getMethod() const {
+ return frames.as<T>();
+ }
+
+ template <class T> bool isA() const {
+ return frames.isA<T>();
+ }
+
+ uint32_t getRequiredCredit() const;
+
+ void encode(framing::Buffer& buffer) const;
+ void encodeContent(framing::Buffer& buffer) const;
+
+ /**
+ * @returns the size of the buffer needed to encode this
+ * message in its entirety
+ */
+ uint32_t encodedSize() const;
+ /**
+ * @returns the size of the buffer needed to encode the
+ * 'header' of this message (not just the header frame,
+ * but other meta data e.g.routing key and exchange)
+ */
+ uint32_t encodedHeaderSize() const;
+ uint32_t encodedContentSize() const;
+
+ void decodeHeader(framing::Buffer& buffer);
+ void decodeContent(framing::Buffer& buffer);
+
+ /**
+ * Releases the in-memory content data held by this
+ * message. Must pass in a store from which the data can
+ * be reloaded.
+ */
+ void releaseContent(MessageStore* store);
+ void destroy();
+
+ void sendContent(Queue& queue, framing::FrameHandler& out, uint16_t maxFrameSize) const;
+ void sendHeader(framing::FrameHandler& out, uint16_t maxFrameSize) const;
+
+ bool isContentLoaded() const;
+
+ bool isExcluded(const std::vector<std::string>& excludes) const;
+ void addTraceId(const std::string& id);
+
+ void forcePersistent();
+
+ boost::intrusive_ptr<Message>& getReplacementMessage(const Queue* qfor) const;
+ void setReplacementMessage(boost::intrusive_ptr<Message> msg, const Queue* qfor);
+
+ /** Call cb when enqueue is complete, may call immediately. Holds cb by reference. */
+ void setEnqueueCompleteCallback(MessageCallback& cb);
+ void resetEnqueueCompleteCallback();
+
+ /** Call cb when dequeue is complete, may call immediately. Holds cb by reference. */
+ void setDequeueCompleteCallback(MessageCallback& cb);
+ void resetDequeueCompleteCallback();
+
+ private:
+ typedef std::map<const Queue*,boost::intrusive_ptr<Message> > Replacement;
+
+ MessageAdapter& getAdapter() const;
+ void allEnqueuesComplete();
+ void allDequeuesComplete();
+
+ mutable sys::Mutex lock;
+ framing::FrameSet frames;
+ mutable boost::shared_ptr<Exchange> exchange;
+ mutable uint64_t persistenceId;
+ bool redelivered;
+ bool loaded;
+ bool staged;
+ bool forcePersistentPolicy; // used to force message as durable, via a broker policy
+ ConnectionToken* publisher;
+ mutable MessageAdapter* adapter;
+ qpid::sys::AbsTime expiration;
+
+ static TransferAdapter TRANSFER;
+
+ mutable Replacement replacement;
+ mutable boost::intrusive_ptr<Message> empty;
+ MessageCallback* enqueueCallback;
+ MessageCallback* dequeueCallback;
+};
+
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/MessageAdapter.cpp b/RC9/qpid/cpp/src/qpid/broker/MessageAdapter.cpp
new file mode 100644
index 0000000000..12f01494de
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/MessageAdapter.cpp
@@ -0,0 +1,70 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "MessageAdapter.h"
+
+#include "qpid/framing/DeliveryProperties.h"
+#include "qpid/framing/MessageProperties.h"
+#include "qpid/framing/MessageTransferBody.h"
+
+namespace {
+ const std::string empty;
+}
+
+namespace qpid {
+namespace broker{
+
+ std::string TransferAdapter::getRoutingKey(const framing::FrameSet& f)
+ {
+ const framing::DeliveryProperties* p = f.getHeaders()->get<framing::DeliveryProperties>();
+ return p ? p->getRoutingKey() : empty;
+ }
+
+ std::string TransferAdapter::getExchange(const framing::FrameSet& f)
+ {
+ return f.as<framing::MessageTransferBody>()->getDestination();
+ }
+
+ bool TransferAdapter::isImmediate(const framing::FrameSet&)
+ {
+ //TODO: delete this, immediate is no longer part of the spec
+ return false;
+ }
+
+ const framing::FieldTable* TransferAdapter::getApplicationHeaders(const framing::FrameSet& f)
+ {
+ const framing::MessageProperties* p = f.getHeaders()->get<framing::MessageProperties>();
+ return p ? &(p->getApplicationHeaders()) : 0;
+ }
+
+ bool TransferAdapter::isPersistent(const framing::FrameSet& f)
+ {
+ const framing::DeliveryProperties* p = f.getHeaders()->get<framing::DeliveryProperties>();
+ return p && p->getDeliveryMode() == 2;
+ }
+
+ bool TransferAdapter::requiresAccept(const framing::FrameSet& f)
+ {
+ const framing::MessageTransferBody* b = f.as<framing::MessageTransferBody>();
+ return b && b->getAcceptMode() == 0/*EXPLICIT == 0*/;
+ }
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/broker/MessageAdapter.h b/RC9/qpid/cpp/src/qpid/broker/MessageAdapter.h
new file mode 100644
index 0000000000..61a1bc4794
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/MessageAdapter.h
@@ -0,0 +1,58 @@
+#ifndef _broker_MessageAdapter_h
+#define _broker_MessageAdapter_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <string>
+#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/FrameSet.h"
+
+namespace qpid {
+namespace broker {
+
+// TODO aconway 2007-11-09: No longer needed, we only have one type of message.
+struct MessageAdapter
+{
+ virtual ~MessageAdapter() {}
+
+ virtual std::string getRoutingKey(const framing::FrameSet& f) = 0;
+ virtual std::string getExchange(const framing::FrameSet& f) = 0;
+ virtual bool isImmediate(const framing::FrameSet& f) = 0;
+ virtual const framing::FieldTable* getApplicationHeaders(const framing::FrameSet& f) = 0;
+ virtual bool isPersistent(const framing::FrameSet& f) = 0;
+ virtual bool requiresAccept(const framing::FrameSet& f) = 0;
+};
+
+struct TransferAdapter : MessageAdapter
+{
+ virtual std::string getRoutingKey(const framing::FrameSet& f);
+ virtual std::string getExchange(const framing::FrameSet& f);
+ virtual const framing::FieldTable* getApplicationHeaders(const framing::FrameSet& f);
+ virtual bool isPersistent(const framing::FrameSet& f);
+ bool isImmediate(const framing::FrameSet&);
+ bool requiresAccept(const framing::FrameSet& f);
+};
+
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/MessageBuilder.cpp b/RC9/qpid/cpp/src/qpid/broker/MessageBuilder.cpp
new file mode 100644
index 0000000000..8f0e3344d5
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/MessageBuilder.cpp
@@ -0,0 +1,128 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "MessageBuilder.h"
+
+#include "Message.h"
+#include "MessageStore.h"
+#include "NullMessageStore.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/reply_exceptions.h"
+
+using boost::intrusive_ptr;
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+namespace
+{
+ std::string type_str(uint8_t type);
+}
+MessageBuilder::MessageBuilder(MessageStore* const _store, uint64_t _stagingThreshold) :
+ state(DORMANT), store(_store), stagingThreshold(_stagingThreshold), staging(false) {}
+
+void MessageBuilder::handle(AMQFrame& frame)
+{
+ uint8_t type = frame.getBody()->type();
+ switch(state) {
+ case METHOD:
+ checkType(METHOD_BODY, type);
+ state = HEADER;
+ break;
+ case HEADER:
+ if (type == CONTENT_BODY) {
+ //TODO: rethink how to handle non-existent headers(?)...
+ //didn't get a header: add in a dummy
+ AMQFrame header;
+ header.setBody(AMQHeaderBody());
+ header.setBof(false);
+ header.setEof(false);
+ message->getFrames().append(header);
+ } else if (type != HEADER_BODY) {
+ throw CommandInvalidException(
+ QPID_MSG("Invalid frame sequence for message, expected header or content got "
+ << type_str(type) << ")"));
+ }
+ state = CONTENT;
+ break;
+ case CONTENT:
+ checkType(CONTENT_BODY, type);
+ break;
+ default:
+ throw CommandInvalidException(QPID_MSG("Invalid frame sequence for message (state=" << state << ")"));
+ }
+ if (staging) {
+ intrusive_ptr<const PersistableMessage> cpmsg = boost::static_pointer_cast<const PersistableMessage>(message);
+ store->appendContent(cpmsg, frame.castBody<AMQContentBody>()->getData());
+ } else {
+ message->getFrames().append(frame);
+ //have we reached the staging limit? if so stage message and release content
+ if (state == CONTENT
+ && stagingThreshold
+ && message->getFrames().getContentSize() >= stagingThreshold
+ && !NullMessageStore::isNullStore(store))
+ {
+ message->releaseContent(store);
+ staging = true;
+ }
+ }
+}
+
+void MessageBuilder::end()
+{
+ message = 0;
+ state = DORMANT;
+ staging = false;
+}
+
+void MessageBuilder::start(const SequenceNumber& id)
+{
+ message = intrusive_ptr<Message>(new Message(id));
+ state = METHOD;
+ staging = false;
+}
+
+namespace {
+
+const std::string HEADER_BODY_S = "HEADER";
+const std::string METHOD_BODY_S = "METHOD";
+const std::string CONTENT_BODY_S = "CONTENT";
+const std::string HEARTBEAT_BODY_S = "HEARTBEAT";
+const std::string UNKNOWN = "unknown";
+
+std::string type_str(uint8_t type)
+{
+ switch(type) {
+ case METHOD_BODY: return METHOD_BODY_S;
+ case HEADER_BODY: return HEADER_BODY_S;
+ case CONTENT_BODY: return CONTENT_BODY_S;
+ case HEARTBEAT_BODY: return HEARTBEAT_BODY_S;
+ }
+ return UNKNOWN;
+}
+
+}
+
+void MessageBuilder::checkType(uint8_t expected, uint8_t actual)
+{
+ if (expected != actual) {
+ throw CommandInvalidException(QPID_MSG("Invalid frame sequence for message (expected "
+ << type_str(expected) << " got " << type_str(actual) << ")"));
+ }
+}
diff --git a/RC9/qpid/cpp/src/qpid/broker/MessageBuilder.h b/RC9/qpid/cpp/src/qpid/broker/MessageBuilder.h
new file mode 100644
index 0000000000..395de024ab
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/MessageBuilder.h
@@ -0,0 +1,57 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _MessageBuilder_
+#define _MessageBuilder_
+
+#include "qpid/framing/FrameHandler.h"
+#include "qpid/framing/SequenceNumber.h"
+#include "qpid/RefCounted.h"
+
+#include <boost/intrusive_ptr.hpp>
+
+namespace qpid {
+ namespace broker {
+ class Message;
+ class MessageStore;
+
+ class MessageBuilder : public framing::FrameHandler{
+ public:
+ MessageBuilder(MessageStore* const store, uint64_t stagingThreshold);
+ void handle(framing::AMQFrame& frame);
+ boost::intrusive_ptr<Message> getMessage() { return message; }
+ void start(const framing::SequenceNumber& id);
+ void end();
+ private:
+ enum State {DORMANT, METHOD, HEADER, CONTENT};
+ State state;
+ boost::intrusive_ptr<Message> message;
+ MessageStore* const store;
+ const uint64_t stagingThreshold;
+ bool staging;
+
+ void checkType(uint8_t expected, uint8_t actual);
+ };
+ }
+}
+
+
+#endif
+
diff --git a/RC9/qpid/cpp/src/qpid/broker/MessageStore.h b/RC9/qpid/cpp/src/qpid/broker/MessageStore.h
new file mode 100644
index 0000000000..4c4c21dfba
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/MessageStore.h
@@ -0,0 +1,199 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _MessageStore_
+#define _MessageStore_
+
+#include "PersistableExchange.h"
+#include "PersistableMessage.h"
+#include "PersistableQueue.h"
+#include "PersistableConfig.h"
+#include "RecoveryManager.h"
+#include "TransactionalStore.h"
+#include "qpid/framing/FieldTable.h"
+
+#include <qpid/Options.h>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/intrusive_ptr.hpp>
+
+namespace qpid {
+namespace broker {
+
+/**
+ * An abstraction of the persistent storage for messages. (In
+ * all methods, any pointers/references to queues or messages
+ * are valid only for the duration of the call).
+ */
+class MessageStore : public TransactionalStore, public Recoverable {
+ public:
+
+ /**
+ * init the store, call before any other call. If not called, store
+ * is free to pick any defaults
+ *
+ * @param options Options object provided by concrete store plug in.
+ */
+ virtual bool init(const Options* options) = 0;
+
+ /**
+ * Record the existence of a durable queue
+ */
+ virtual void create(PersistableQueue& queue,
+ const framing::FieldTable& args) = 0;
+ /**
+ * Destroy a durable queue
+ */
+ virtual void destroy(PersistableQueue& queue) = 0;
+
+ /**
+ * Record the existence of a durable exchange
+ */
+ virtual void create(const PersistableExchange& exchange,
+ const framing::FieldTable& args) = 0;
+ /**
+ * Destroy a durable exchange
+ */
+ virtual void destroy(const PersistableExchange& exchange) = 0;
+
+ /**
+ * Record a binding
+ */
+ virtual void bind(const PersistableExchange& exchange, const PersistableQueue& queue,
+ const std::string& key, const framing::FieldTable& args) = 0;
+
+ /**
+ * Forget a binding
+ */
+ virtual void unbind(const PersistableExchange& exchange, const PersistableQueue& queue,
+ const std::string& key, const framing::FieldTable& args) = 0;
+
+ /**
+ * Record generic durable configuration
+ */
+ virtual void create(const PersistableConfig& config) = 0;
+
+ /**
+ * Destroy generic durable configuration
+ */
+ virtual void destroy(const PersistableConfig& config) = 0;
+
+ /**
+ * Stores a messages before it has been enqueued
+ * (enqueueing automatically stores the message so this is
+ * only required if storage is required prior to that
+ * point). If the message has not yet been stored it will
+ * store the headers as well as any content passed in. A
+ * persistence id will be set on the message which can be
+ * used to load the content or to append to it.
+ */
+ virtual void stage(const boost::intrusive_ptr<PersistableMessage>& msg) = 0;
+
+ /**
+ * Destroys a previously staged message. This only needs
+ * to be called if the message is never enqueued. (Once
+ * enqueued, deletion will be automatic when the message
+ * is dequeued from all queues it was enqueued onto).
+ */
+ virtual void destroy(PersistableMessage& msg) = 0;
+
+ /**
+ * Appends content to a previously staged message
+ */
+ virtual void appendContent(const boost::intrusive_ptr<const PersistableMessage>& msg,
+ const std::string& data) = 0;
+
+ /**
+ * Loads (a section) of content data for the specified
+ * message (previously stored through a call to stage or
+ * enqueue) into data. The offset refers to the content
+ * only (i.e. an offset of 0 implies that the start of the
+ * content should be loaded, not the headers or related
+ * meta-data).
+ */
+ virtual void loadContent(const qpid::broker::PersistableQueue& queue,
+ const boost::intrusive_ptr<const PersistableMessage>& msg,
+ std::string& data, uint64_t offset, uint32_t length) = 0;
+
+ /**
+ * Enqueues a message, storing the message if it has not
+ * been previously stored and recording that the given
+ * message is on the given queue.
+ *
+ * Note: that this is async so the return of the function does
+ * not mean the opperation is complete.
+ *
+ * @param msg the message to enqueue
+ * @param queue the name of the queue onto which it is to be enqueued
+ * @param xid (a pointer to) an identifier of the
+ * distributed transaction in which the operation takes
+ * place or null for 'local' transactions
+ */
+ virtual void enqueue(TransactionContext* ctxt,
+ const boost::intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue& queue) = 0;
+
+ /**
+ * Dequeues a message, recording that the given message is
+ * no longer on the given queue and deleting the message
+ * if it is no longer on any other queue.
+ *
+ * Note: that this is async so the return of the function does
+ * not mean the opperation is complete.
+ *
+ * @param msg the message to dequeue
+ * @param queue the name of the queue from which it is to be dequeued
+ * @param xid (a pointer to) an identifier of the
+ * distributed transaction in which the operation takes
+ * place or null for 'local' transactions
+ */
+ virtual void dequeue(TransactionContext* ctxt,
+ const boost::intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue& queue) = 0;
+
+ /**
+ * Flushes all async messages to disk for the specified queue
+ *
+ * Note: that this is async so the return of the function does
+ * not mean the opperation is complete.
+ *
+ * @param queue the name of the queue from which it is to be dequeued
+ */
+ virtual void flush(const qpid::broker::PersistableQueue& queue)=0;
+
+ /**
+ * Returns the number of outstanding AIO's for a given queue
+ *
+ * If 0, than all the enqueue / dequeues have been stored
+ * to disk
+ *
+ * @param queue the name of the queue to check for outstanding AIO
+ */
+ virtual uint32_t outstandingQueueAIO(const PersistableQueue& queue) = 0;
+
+
+ virtual ~MessageStore(){}
+};
+
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/MessageStoreModule.cpp b/RC9/qpid/cpp/src/qpid/broker/MessageStoreModule.cpp
new file mode 100644
index 0000000000..96186d508b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/MessageStoreModule.cpp
@@ -0,0 +1,174 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "MessageStoreModule.h"
+#include "NullMessageStore.h"
+#include <iostream>
+
+// This transfer protects against the unloading of the store lib prior to the handling of the exception
+#define TRANSFER_EXCEPTION(fn) try { fn; } catch (std::exception& e) { throw Exception(e.what()); }
+
+using boost::intrusive_ptr;
+using qpid::framing::FieldTable;
+
+namespace qpid {
+namespace broker {
+
+MessageStoreModule::MessageStoreModule(MessageStore* _store) : store(_store) {}
+
+MessageStoreModule::~MessageStoreModule()
+{
+ delete store;
+}
+
+bool MessageStoreModule::init(const Options*) { return true; }
+
+void MessageStoreModule::create(PersistableQueue& queue, const FieldTable& args)
+{
+ TRANSFER_EXCEPTION(store->create(queue, args));
+}
+
+void MessageStoreModule::destroy(PersistableQueue& queue)
+{
+ TRANSFER_EXCEPTION(store->destroy(queue));
+}
+
+void MessageStoreModule::create(const PersistableExchange& exchange, const FieldTable& args)
+{
+ TRANSFER_EXCEPTION(store->create(exchange, args));
+}
+
+void MessageStoreModule::destroy(const PersistableExchange& exchange)
+{
+ TRANSFER_EXCEPTION(store->destroy(exchange));
+}
+
+void MessageStoreModule::bind(const PersistableExchange& e, const PersistableQueue& q,
+ const std::string& k, const framing::FieldTable& a)
+{
+ TRANSFER_EXCEPTION(store->bind(e, q, k, a));
+}
+
+void MessageStoreModule::unbind(const PersistableExchange& e, const PersistableQueue& q,
+ const std::string& k, const framing::FieldTable& a)
+{
+ TRANSFER_EXCEPTION(store->unbind(e, q, k, a));
+}
+
+void MessageStoreModule::create(const PersistableConfig& config)
+{
+ TRANSFER_EXCEPTION(store->create(config));
+}
+
+void MessageStoreModule::destroy(const PersistableConfig& config)
+{
+ TRANSFER_EXCEPTION(store->destroy(config));
+}
+
+void MessageStoreModule::recover(RecoveryManager& registry)
+{
+ TRANSFER_EXCEPTION(store->recover(registry));
+}
+
+void MessageStoreModule::stage(const intrusive_ptr<PersistableMessage>& msg)
+{
+ TRANSFER_EXCEPTION(store->stage(msg));
+}
+
+void MessageStoreModule::destroy(PersistableMessage& msg)
+{
+ TRANSFER_EXCEPTION(store->destroy(msg));
+}
+
+void MessageStoreModule::appendContent(const intrusive_ptr<const PersistableMessage>& msg,
+ const std::string& data)
+{
+ TRANSFER_EXCEPTION(store->appendContent(msg, data));
+}
+
+void MessageStoreModule::loadContent(
+ const qpid::broker::PersistableQueue& queue,
+ const intrusive_ptr<const PersistableMessage>& msg,
+ string& data, uint64_t offset, uint32_t length)
+{
+ TRANSFER_EXCEPTION(store->loadContent(queue, msg, data, offset, length));
+}
+
+void MessageStoreModule::enqueue(TransactionContext* ctxt,
+ const intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue& queue)
+{
+ TRANSFER_EXCEPTION(store->enqueue(ctxt, msg, queue));
+}
+
+void MessageStoreModule::dequeue(TransactionContext* ctxt,
+ const intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue& queue)
+{
+ TRANSFER_EXCEPTION(store->dequeue(ctxt, msg, queue));
+}
+
+void MessageStoreModule::flush(const qpid::broker::PersistableQueue& queue)
+{
+ TRANSFER_EXCEPTION(store->flush(queue));
+}
+
+uint32_t MessageStoreModule::outstandingQueueAIO(const PersistableQueue& queue)
+{
+ TRANSFER_EXCEPTION(return store->outstandingQueueAIO(queue));
+}
+
+std::auto_ptr<TransactionContext> MessageStoreModule::begin()
+{
+ TRANSFER_EXCEPTION(return store->begin());
+}
+
+std::auto_ptr<TPCTransactionContext> MessageStoreModule::begin(const std::string& xid)
+{
+ TRANSFER_EXCEPTION(return store->begin(xid));
+}
+
+void MessageStoreModule::prepare(TPCTransactionContext& txn)
+{
+ TRANSFER_EXCEPTION(store->prepare(txn));
+}
+
+void MessageStoreModule::commit(TransactionContext& ctxt)
+{
+ TRANSFER_EXCEPTION(store->commit(ctxt));
+}
+
+void MessageStoreModule::abort(TransactionContext& ctxt)
+{
+ TRANSFER_EXCEPTION(store->abort(ctxt));
+}
+
+void MessageStoreModule::collectPreparedXids(std::set<std::string>& xids)
+{
+ TRANSFER_EXCEPTION(store->collectPreparedXids(xids));
+}
+
+bool MessageStoreModule::isNull() const
+{
+ return NullMessageStore::isNullStore(store);
+}
+
+}} // namespace qpid::broker
diff --git a/RC9/qpid/cpp/src/qpid/broker/MessageStoreModule.h b/RC9/qpid/cpp/src/qpid/broker/MessageStoreModule.h
new file mode 100644
index 0000000000..0b51610a46
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/MessageStoreModule.h
@@ -0,0 +1,85 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _MessageStoreModule_
+#define _MessageStoreModule_
+
+#include "MessageStore.h"
+#include "Queue.h"
+#include "RecoveryManager.h"
+
+#include <boost/intrusive_ptr.hpp>
+
+namespace qpid {
+namespace broker {
+
+/**
+ * A null implementation of the MessageStore interface
+ */
+class MessageStoreModule : public MessageStore
+{
+ MessageStore* store;
+ public:
+ MessageStoreModule(MessageStore* store);
+
+ bool init(const Options* options);
+ std::auto_ptr<TransactionContext> begin();
+ std::auto_ptr<TPCTransactionContext> begin(const std::string& xid);
+ void prepare(TPCTransactionContext& txn);
+ void commit(TransactionContext& txn);
+ void abort(TransactionContext& txn);
+ void collectPreparedXids(std::set<std::string>& xids);
+
+ void create(PersistableQueue& queue, const framing::FieldTable& args);
+ void destroy(PersistableQueue& queue);
+ void create(const PersistableExchange& exchange, const framing::FieldTable& args);
+ void destroy(const PersistableExchange& exchange);
+ void bind(const PersistableExchange& exchange, const PersistableQueue& queue,
+ const std::string& key, const framing::FieldTable& args);
+ void unbind(const PersistableExchange& exchange, const PersistableQueue& queue,
+ const std::string& key, const framing::FieldTable& args);
+ void create(const PersistableConfig& config);
+ void destroy(const PersistableConfig& config);
+ void recover(RecoveryManager& queues);
+ void stage(const boost::intrusive_ptr<PersistableMessage>& msg);
+ void destroy(PersistableMessage& msg);
+ void appendContent(const boost::intrusive_ptr<const PersistableMessage>& msg, const std::string& data);
+ void loadContent(const qpid::broker::PersistableQueue& queue,
+ const boost::intrusive_ptr<const PersistableMessage>& msg, std::string& data,
+ uint64_t offset, uint32_t length);
+
+ void enqueue(TransactionContext* ctxt,
+ const boost::intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue& queue);
+ void dequeue(TransactionContext* ctxt,
+ const boost::intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue& queue);
+ uint32_t outstandingQueueAIO(const PersistableQueue& queue);
+ void flush(const qpid::broker::PersistableQueue& queue);
+ bool isNull() const;
+
+ ~MessageStoreModule();
+};
+
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/NameGenerator.cpp b/RC9/qpid/cpp/src/qpid/broker/NameGenerator.cpp
new file mode 100644
index 0000000000..8484f921e9
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/NameGenerator.cpp
@@ -0,0 +1,32 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "NameGenerator.h"
+#include <sstream>
+
+using namespace qpid::broker;
+
+NameGenerator::NameGenerator(const std::string& _base) : base(_base), counter(1) {}
+
+std::string NameGenerator::generate(){
+ std::stringstream ss;
+ ss << base << counter++;
+ return ss.str();
+}
diff --git a/RC9/qpid/cpp/src/qpid/broker/NameGenerator.h b/RC9/qpid/cpp/src/qpid/broker/NameGenerator.h
new file mode 100644
index 0000000000..6ea25c9797
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/NameGenerator.h
@@ -0,0 +1,39 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _NameGenerator_
+#define _NameGenerator_
+
+#include <string>
+
+namespace qpid {
+ namespace broker {
+ class NameGenerator{
+ const std::string base;
+ unsigned int counter;
+ public:
+ NameGenerator(const std::string& base);
+ std::string generate();
+ };
+ }
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/NullMessageStore.cpp b/RC9/qpid/cpp/src/qpid/broker/NullMessageStore.cpp
new file mode 100644
index 0000000000..ad0143ce43
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/NullMessageStore.cpp
@@ -0,0 +1,166 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "NullMessageStore.h"
+#include "MessageStoreModule.h"
+#include "RecoveryManager.h"
+#include "qpid/log/Statement.h"
+#include "qpid/framing/reply_exceptions.h"
+
+#include <iostream>
+
+using boost::intrusive_ptr;
+
+namespace qpid{
+namespace broker{
+
+const std::string nullxid = "";
+
+class SimpleDummyCtxt : public TransactionContext {};
+
+class DummyCtxt : public TPCTransactionContext
+{
+ const std::string xid;
+public:
+ DummyCtxt(const std::string& _xid) : xid(_xid) {}
+ static std::string getXid(TransactionContext& ctxt)
+ {
+ DummyCtxt* c(dynamic_cast<DummyCtxt*>(&ctxt));
+ return c ? c->xid : nullxid;
+ }
+};
+
+NullMessageStore::NullMessageStore() : nextPersistenceId(1) {
+ QPID_LOG(info, "No message store configured, persistence is disabled.")
+}
+
+bool NullMessageStore::init(const Options* /*options*/) {return true;}
+
+void NullMessageStore::create(PersistableQueue& queue, const framing::FieldTable& /*args*/)
+{
+ queue.setPersistenceId(nextPersistenceId++);
+}
+
+void NullMessageStore::destroy(PersistableQueue&)
+{
+}
+
+void NullMessageStore::create(const PersistableExchange& exchange, const framing::FieldTable& /*args*/)
+{
+ exchange.setPersistenceId(nextPersistenceId++);
+}
+
+void NullMessageStore::destroy(const PersistableExchange& )
+{}
+
+void NullMessageStore::bind(const PersistableExchange&, const PersistableQueue&, const std::string&, const framing::FieldTable&){}
+
+void NullMessageStore::unbind(const PersistableExchange&, const PersistableQueue&, const std::string&, const framing::FieldTable&){}
+
+void NullMessageStore::create(const PersistableConfig& config)
+{
+ config.setPersistenceId(nextPersistenceId++);
+}
+
+void NullMessageStore::destroy(const PersistableConfig&) {}
+
+void NullMessageStore::recover(RecoveryManager&) {}
+
+void NullMessageStore::stage(const intrusive_ptr<PersistableMessage>&) {}
+
+void NullMessageStore::destroy(PersistableMessage&) {}
+
+void NullMessageStore::appendContent(const intrusive_ptr<const PersistableMessage>&, const string&) {}
+
+void NullMessageStore::loadContent(const qpid::broker::PersistableQueue&,
+ const intrusive_ptr<const PersistableMessage>&,
+ string&, uint64_t, uint32_t)
+{
+ throw qpid::framing::InternalErrorException("Can't load content; persistence not enabled");
+}
+
+void NullMessageStore::enqueue(TransactionContext*,
+ const intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue&)
+{
+ msg->enqueueComplete();
+}
+
+void NullMessageStore::dequeue(TransactionContext*,
+ const intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue&)
+{
+ msg->dequeueComplete();
+}
+
+void NullMessageStore::flush(const qpid::broker::PersistableQueue&) {}
+
+uint32_t NullMessageStore::outstandingQueueAIO(const PersistableQueue& ) {
+ return 0;
+}
+
+std::auto_ptr<TransactionContext> NullMessageStore::begin()
+{
+ return std::auto_ptr<TransactionContext>(new SimpleDummyCtxt());
+}
+
+std::auto_ptr<TPCTransactionContext> NullMessageStore::begin(const std::string& xid)
+{
+ return std::auto_ptr<TPCTransactionContext>(new DummyCtxt(xid));
+}
+
+void NullMessageStore::prepare(TPCTransactionContext& ctxt)
+{
+ prepared.insert(DummyCtxt::getXid(ctxt));
+}
+
+void NullMessageStore::commit(TransactionContext& ctxt)
+{
+ prepared.erase(DummyCtxt::getXid(ctxt));
+}
+
+void NullMessageStore::abort(TransactionContext& ctxt)
+{
+ prepared.erase(DummyCtxt::getXid(ctxt));
+}
+
+void NullMessageStore::collectPreparedXids(std::set<string>& out)
+{
+ out.insert(prepared.begin(), prepared.end());
+}
+
+bool NullMessageStore::isNull() const
+{
+ return true;
+}
+
+bool NullMessageStore::isNullStore(const MessageStore* store)
+{
+ const MessageStoreModule* wrapper = dynamic_cast<const MessageStoreModule*>(store);
+ if (wrapper) {
+ return wrapper->isNull();
+ } else {
+ const NullMessageStore* test = dynamic_cast<const NullMessageStore*>(store);
+ return test && test->isNull();
+ }
+}
+
+}} // namespace qpid::broker
diff --git a/RC9/qpid/cpp/src/qpid/broker/NullMessageStore.h b/RC9/qpid/cpp/src/qpid/broker/NullMessageStore.h
new file mode 100644
index 0000000000..d99c751d26
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/NullMessageStore.h
@@ -0,0 +1,88 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _NullMessageStore_
+#define _NullMessageStore_
+
+#include <set>
+#include "MessageStore.h"
+#include "Queue.h"
+
+#include <boost/intrusive_ptr.hpp>
+
+namespace qpid {
+namespace broker {
+
+/**
+ * A null implementation of the MessageStore interface
+ */
+class NullMessageStore : public MessageStore
+{
+ std::set<std::string> prepared;
+ uint64_t nextPersistenceId;
+ public:
+ NullMessageStore();
+
+ virtual bool init(const Options* options);
+ virtual std::auto_ptr<TransactionContext> begin();
+ virtual std::auto_ptr<TPCTransactionContext> begin(const std::string& xid);
+ virtual void prepare(TPCTransactionContext& txn);
+ virtual void commit(TransactionContext& txn);
+ virtual void abort(TransactionContext& txn);
+ virtual void collectPreparedXids(std::set<std::string>& xids);
+
+ virtual void create(PersistableQueue& queue, const framing::FieldTable& args);
+ virtual void destroy(PersistableQueue& queue);
+ virtual void create(const PersistableExchange& exchange, const framing::FieldTable& args);
+ virtual void destroy(const PersistableExchange& exchange);
+
+ virtual void bind(const PersistableExchange& exchange, const PersistableQueue& queue,
+ const std::string& key, const framing::FieldTable& args);
+ virtual void unbind(const PersistableExchange& exchange, const PersistableQueue& queue,
+ const std::string& key, const framing::FieldTable& args);
+ virtual void create(const PersistableConfig& config);
+ virtual void destroy(const PersistableConfig& config);
+ virtual void recover(RecoveryManager& queues);
+ virtual void stage(const boost::intrusive_ptr<PersistableMessage>& msg);
+ virtual void destroy(PersistableMessage& msg);
+ virtual void appendContent(const boost::intrusive_ptr<const PersistableMessage>& msg,
+ const std::string& data);
+ virtual void loadContent(const qpid::broker::PersistableQueue& queue,
+ const boost::intrusive_ptr<const PersistableMessage>& msg, std::string& data,
+ uint64_t offset, uint32_t length);
+ virtual void enqueue(TransactionContext* ctxt,
+ const boost::intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue& queue);
+ virtual void dequeue(TransactionContext* ctxt,
+ const boost::intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue& queue);
+ virtual uint32_t outstandingQueueAIO(const PersistableQueue& queue);
+ virtual void flush(const qpid::broker::PersistableQueue& queue);
+ ~NullMessageStore(){}
+
+ virtual bool isNull() const;
+ static bool isNullStore(const MessageStore*);
+};
+
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/OwnershipToken.h b/RC9/qpid/cpp/src/qpid/broker/OwnershipToken.h
new file mode 100644
index 0000000000..effd2f5b3c
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/OwnershipToken.h
@@ -0,0 +1,38 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _OwnershipToken_
+#define _OwnershipToken_
+
+namespace qpid {
+namespace broker {
+
+class ConnectionToken;
+
+class OwnershipToken{
+public:
+ virtual bool isLocal(const ConnectionToken* t) const = 0;
+ virtual ~OwnershipToken(){}
+};
+
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/Persistable.h b/RC9/qpid/cpp/src/qpid/broker/Persistable.h
new file mode 100644
index 0000000000..36499c7a1a
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/Persistable.h
@@ -0,0 +1,63 @@
+#ifndef _broker_Persistable_h
+#define _broker_Persistable_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/framing/amqp_types.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/RefCounted.h"
+
+namespace qpid {
+namespace broker {
+
+/**
+ * Base class for all persistable objects
+ */
+class Persistable : public RefCounted
+{
+public:
+ /**
+ * Allows the store to attach its own identifier to this object
+ */
+ virtual void setPersistenceId(uint64_t id) const = 0;
+ /**
+ * Returns any identifier the store may have attached to this
+ * object
+ */
+ virtual uint64_t getPersistenceId() const = 0;
+ /**
+ * Encodes the persistable state of this object into the supplied
+ * buffer
+ */
+ virtual void encode(framing::Buffer& buffer) const = 0;
+ /**
+ * @returns the size of the buffer needed to encode this object
+ */
+ virtual uint32_t encodedSize() const = 0;
+
+ virtual ~Persistable() {};
+};
+
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/PersistableConfig.h b/RC9/qpid/cpp/src/qpid/broker/PersistableConfig.h
new file mode 100644
index 0000000000..914e91ea80
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/PersistableConfig.h
@@ -0,0 +1,45 @@
+#ifndef _broker_PersistableConfig_h
+#define _broker_PersistableConfig_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <string>
+#include "Persistable.h"
+
+namespace qpid {
+namespace broker {
+
+/**
+ * The interface used by general-purpose persistable configuration for
+ * the message store.
+ */
+class PersistableConfig : public Persistable
+{
+public:
+ virtual const std::string& getName() const = 0;
+ virtual ~PersistableConfig() {};
+};
+
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/PersistableExchange.h b/RC9/qpid/cpp/src/qpid/broker/PersistableExchange.h
new file mode 100644
index 0000000000..683b740ddc
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/PersistableExchange.h
@@ -0,0 +1,45 @@
+#ifndef _broker_PersistableExchange_h
+#define _broker_PersistableExchange_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <string>
+#include "Persistable.h"
+
+namespace qpid {
+namespace broker {
+
+/**
+ * The interface exchanges must expose to the MessageStore in order to be
+ * persistable.
+ */
+class PersistableExchange : public Persistable
+{
+public:
+ virtual const std::string& getName() const = 0;
+ virtual ~PersistableExchange() {};
+};
+
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/PersistableMessage.cpp b/RC9/qpid/cpp/src/qpid/broker/PersistableMessage.cpp
new file mode 100644
index 0000000000..4d272c3780
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/PersistableMessage.cpp
@@ -0,0 +1,143 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+
+#include "PersistableMessage.h"
+#include "MessageStore.h"
+#include <iostream>
+
+using namespace qpid::broker;
+
+namespace qpid {
+namespace broker {
+
+class MessageStore;
+
+PersistableMessage::~PersistableMessage() {}
+
+PersistableMessage::PersistableMessage() :
+ asyncEnqueueCounter(0),
+ asyncDequeueCounter(0),
+ contentReleased(false),
+ store(0)
+{}
+
+void PersistableMessage::flush()
+{
+ syncList copy;
+ {
+ sys::ScopedLock<sys::Mutex> l(storeLock);
+ if (store) {
+ copy = synclist;
+ } else {
+ return;//early exit as nothing to do
+ }
+ }
+ for (syncList::iterator i = copy.begin(); i != copy.end(); ++i) {
+ PersistableQueue::shared_ptr q(i->lock());
+ if (q) {
+ store->flush(*q);
+ }
+ }
+}
+
+void PersistableMessage::setContentReleased() {contentReleased = true; }
+
+bool PersistableMessage::isContentReleased()const { return contentReleased; }
+
+bool PersistableMessage::isEnqueueComplete() {
+ sys::ScopedLock<sys::Mutex> l(asyncEnqueueLock);
+ return asyncEnqueueCounter == 0;
+}
+
+void PersistableMessage::enqueueComplete() {
+ bool notify = false;
+ {
+ sys::ScopedLock<sys::Mutex> l(asyncEnqueueLock);
+ if (asyncEnqueueCounter > 0) {
+ if (--asyncEnqueueCounter == 0) {
+ notify = true;
+ }
+ }
+ }
+ if (notify) {
+ allEnqueuesComplete();
+ sys::ScopedLock<sys::Mutex> l(storeLock);
+ if (store) {
+ for (syncList::iterator i = synclist.begin(); i != synclist.end(); ++i) {
+ PersistableQueue::shared_ptr q(i->lock());
+ if (q) q->notifyDurableIOComplete();
+ }
+ }
+ }
+}
+
+void PersistableMessage::enqueueAsync(PersistableQueue::shared_ptr queue, MessageStore* _store) {
+ if (_store){
+ sys::ScopedLock<sys::Mutex> l(storeLock);
+ store = _store;
+ boost::weak_ptr<PersistableQueue> q(queue);
+ synclist.push_back(q);
+ }
+ enqueueAsync();
+}
+
+void PersistableMessage::enqueueAsync() {
+ sys::ScopedLock<sys::Mutex> l(asyncEnqueueLock);
+ asyncEnqueueCounter++;
+}
+
+bool PersistableMessage::isDequeueComplete() {
+ sys::ScopedLock<sys::Mutex> l(asyncDequeueLock);
+ return asyncDequeueCounter == 0;
+}
+
+void PersistableMessage::dequeueComplete() {
+ bool notify = false;
+ {
+ sys::ScopedLock<sys::Mutex> l(asyncDequeueLock);
+ if (asyncDequeueCounter > 0) {
+ if (--asyncDequeueCounter == 0) {
+ notify = true;
+ }
+ }
+ }
+ if (notify) allDequeuesComplete();
+}
+
+void PersistableMessage::dequeueAsync(PersistableQueue::shared_ptr queue, MessageStore* _store) {
+ if (_store){
+ sys::ScopedLock<sys::Mutex> l(storeLock);
+ store = _store;
+ boost::weak_ptr<PersistableQueue> q(queue);
+ synclist.push_back(q);
+ }
+ dequeueAsync();
+}
+
+void PersistableMessage::dequeueAsync() {
+ sys::ScopedLock<sys::Mutex> l(asyncDequeueLock);
+ asyncDequeueCounter++;
+}
+
+}}
+
+
diff --git a/RC9/qpid/cpp/src/qpid/broker/PersistableMessage.h b/RC9/qpid/cpp/src/qpid/broker/PersistableMessage.h
new file mode 100644
index 0000000000..4f2e3abafa
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/PersistableMessage.h
@@ -0,0 +1,116 @@
+#ifndef _broker_PersistableMessage_h
+#define _broker_PersistableMessage_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <string>
+#include <list>
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+#include "Persistable.h"
+#include "qpid/framing/amqp_types.h"
+#include "qpid/sys/Mutex.h"
+#include "PersistableQueue.h"
+
+namespace qpid {
+namespace broker {
+
+class MessageStore;
+
+/**
+ * Base class for persistable messages.
+ */
+class PersistableMessage : public Persistable
+{
+ typedef std::list< boost::weak_ptr<PersistableQueue> > syncList;
+ sys::Mutex asyncEnqueueLock;
+ sys::Mutex asyncDequeueLock;
+ sys::Mutex storeLock;
+
+ /**
+ * Tracks the number of outstanding asynchronous enqueue
+ * operations. When the message is enqueued asynchronously the
+ * count is incremented; when that enqueue completes it is
+ * decremented. Thus when it is 0, there are no outstanding
+ * enqueues.
+ */
+ int asyncEnqueueCounter;
+
+ /**
+ * Tracks the number of outstanding asynchronous dequeue
+ * operations. When the message is dequeued asynchronously the
+ * count is incremented; when that dequeue completes it is
+ * decremented. Thus when it is 0, there are no outstanding
+ * dequeues.
+ */
+ int asyncDequeueCounter;
+
+ bool contentReleased;
+ syncList synclist;
+
+ protected:
+ /** Called when all enqueues are complete for this message. */
+ virtual void allEnqueuesComplete() = 0;
+ /** Called when all dequeues are complete for this message. */
+ virtual void allDequeuesComplete() = 0;
+
+ void setContentReleased();
+
+ MessageStore* store;
+
+ public:
+ typedef boost::shared_ptr<PersistableMessage> shared_ptr;
+
+ /**
+ * @returns the size of the headers when encoded
+ */
+ virtual uint32_t encodedHeaderSize() const = 0;
+
+ virtual ~PersistableMessage();
+
+ PersistableMessage();
+
+ void flush();
+
+ bool isContentReleased() const;
+
+ bool isEnqueueComplete();
+
+ void enqueueComplete();
+
+ void enqueueAsync(PersistableQueue::shared_ptr queue, MessageStore* _store);
+
+ void enqueueAsync();
+
+ bool isDequeueComplete();
+
+ void dequeueComplete();
+
+ void dequeueAsync(PersistableQueue::shared_ptr queue, MessageStore* _store);
+
+ void dequeueAsync();
+};
+
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/PersistableQueue.h b/RC9/qpid/cpp/src/qpid/broker/PersistableQueue.h
new file mode 100644
index 0000000000..9236814ae3
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/PersistableQueue.h
@@ -0,0 +1,87 @@
+#ifndef _broker_PersistableQueue_h
+#define _broker_PersistableQueue_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <string>
+#include "Persistable.h"
+#include "qpid/management/Manageable.h"
+#include <boost/shared_ptr.hpp>
+
+namespace qpid {
+namespace broker {
+
+
+/**
+* Empty class to be used by any module that wanted to set an external per queue store into
+* persistableQueue
+*/
+
+class ExternalQueueStore : public management::Manageable
+{
+public:
+ virtual ~ExternalQueueStore() {};
+
+};
+
+
+/**
+ * The interface queues must expose to the MessageStore in order to be
+ * persistable.
+ */
+class PersistableQueue : public Persistable
+{
+public:
+ typedef boost::shared_ptr<PersistableQueue> shared_ptr;
+
+ virtual const std::string& getName() const = 0;
+ virtual ~PersistableQueue() {
+ if (externalQueueStore)
+ delete externalQueueStore;
+ };
+
+ virtual void setExternalQueueStore(ExternalQueueStore* inst) = 0;
+
+ inline ExternalQueueStore* getExternalQueueStore() const {return externalQueueStore;};
+
+ PersistableQueue():externalQueueStore(NULL){
+ };
+
+
+ /**
+ * call back to signal async AIO writes have
+ * completed (enqueue/dequeue etc)
+ *
+ * Note: DO NOT do work on this callback, if you block
+ * this callback you will block the store.
+ */
+ virtual void notifyDurableIOComplete() = 0;
+protected:
+
+ ExternalQueueStore* externalQueueStore;
+
+};
+
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/Queue.cpp b/RC9/qpid/cpp/src/qpid/broker/Queue.cpp
new file mode 100644
index 0000000000..9089ba0c54
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/Queue.cpp
@@ -0,0 +1,900 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Broker.h"
+#include "Queue.h"
+#include "Exchange.h"
+#include "DeliverableMessage.h"
+#include "MessageStore.h"
+#include "NullMessageStore.h"
+#include "QueueRegistry.h"
+
+#include "qpid/StringUtils.h"
+#include "qpid/log/Statement.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/sys/Monitor.h"
+#include "qpid/sys/Time.h"
+#include "qmf/org/apache/qpid/broker/ArgsQueuePurge.h"
+
+#include <iostream>
+#include <algorithm>
+#include <functional>
+
+#include <boost/bind.hpp>
+#include <boost/intrusive_ptr.hpp>
+
+using namespace qpid::broker;
+using namespace qpid::sys;
+using namespace qpid::framing;
+using qpid::management::ManagementAgent;
+using qpid::management::ManagementObject;
+using qpid::management::Manageable;
+using qpid::management::Args;
+using std::for_each;
+using std::mem_fun;
+namespace _qmf = qmf::org::apache::qpid::broker;
+
+
+namespace
+{
+const std::string qpidMaxSize("qpid.max_size");
+const std::string qpidMaxCount("qpid.max_count");
+const std::string qpidNoLocal("no-local");
+const std::string qpidTraceIdentity("qpid.trace.id");
+const std::string qpidTraceExclude("qpid.trace.exclude");
+const std::string qpidLastValueQueue("qpid.last_value_queue");
+const std::string qpidLastValueQueueNoBrowse("qpid.last_value_queue_no_browse");
+const std::string qpidPersistLastNode("qpid.persist_last_node");
+const std::string qpidVQMatchProperty("qpid.LVQ_key");
+}
+
+
+Queue::Queue(const string& _name, bool _autodelete,
+ MessageStore* const _store,
+ const OwnershipToken* const _owner,
+ Manageable* parent) :
+
+ name(_name),
+ autodelete(_autodelete),
+ store(_store),
+ owner(_owner),
+ consumerCount(0),
+ exclusive(0),
+ noLocal(false),
+ lastValueQueue(false),
+ lastValueQueueNoBrowse(false),
+ persistLastNode(false),
+ inLastNodeFailure(false),
+ persistenceId(0),
+ policyExceeded(false),
+ mgmtObject(0)
+{
+ if (parent != 0)
+ {
+ ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+
+ if (agent != 0)
+ {
+ mgmtObject = new _qmf::Queue(agent, this, parent, _name, _store != 0, _autodelete, _owner != 0);
+
+ // Add the object to the management agent only if this queue is not durable.
+ // If it's durable, we will add it later when the queue is assigned a persistenceId.
+ if (store == 0)
+ agent->addObject (mgmtObject);
+ }
+ }
+}
+
+Queue::~Queue()
+{
+ if (mgmtObject != 0)
+ mgmtObject->resourceDestroy ();
+}
+
+void Queue::notifyDurableIOComplete()
+{
+ QueueListeners::NotificationSet copy;
+ {
+ Mutex::ScopedLock locker(messageLock);
+ listeners.populate(copy);
+ }
+ copy.notify();
+}
+
+bool isLocalTo(const OwnershipToken* token, boost::intrusive_ptr<Message>& msg)
+{
+ return token && token->isLocal(msg->getPublisher());
+}
+
+bool Queue::isLocal(boost::intrusive_ptr<Message>& msg)
+{
+ //message is considered local if it was published on the same
+ //connection as that of the session which declared this queue
+ //exclusive (owner) or which has an exclusive subscription
+ //(exclusive)
+ return noLocal && (isLocalTo(owner, msg) || isLocalTo(exclusive, msg));
+}
+
+bool Queue::isExcluded(boost::intrusive_ptr<Message>& msg)
+{
+ return traceExclude.size() && msg->isExcluded(traceExclude);
+}
+
+void Queue::deliver(boost::intrusive_ptr<Message>& msg){
+
+ if (msg->isImmediate() && getConsumerCount() == 0) {
+ if (alternateExchange) {
+ DeliverableMessage deliverable(msg);
+ alternateExchange->route(deliverable, msg->getRoutingKey(), msg->getApplicationHeaders());
+ }
+ } else if (isLocal(msg)) {
+ //drop message
+ QPID_LOG(info, "Dropping 'local' message from " << getName());
+ } else if (isExcluded(msg)) {
+ //drop message
+ QPID_LOG(info, "Dropping excluded message from " << getName());
+ } else {
+ // if no store then mark as enqueued
+ if (!enqueue(0, msg)){
+ push(msg);
+ msg->enqueueComplete();
+ }else {
+ push(msg);
+ }
+ mgntEnqStats(msg);
+ QPID_LOG(debug, "Message " << msg << " enqueued on " << name << "[" << this << "]");
+ }
+}
+
+
+void Queue::recover(boost::intrusive_ptr<Message>& msg){
+ push(msg);
+ msg->enqueueComplete(); // mark the message as enqueued
+ mgntEnqStats(msg);
+
+ if (store && !msg->isContentLoaded()) {
+ //content has not been loaded, need to ensure that lazy loading mode is set:
+ //TODO: find a nicer way to do this
+ msg->releaseContent(store);
+ }
+}
+
+void Queue::process(boost::intrusive_ptr<Message>& msg){
+ push(msg);
+ mgntEnqStats(msg);
+ if (mgmtObject != 0){
+ mgmtObject->inc_msgTxnEnqueues ();
+ mgmtObject->inc_byteTxnEnqueues (msg->contentSize ());
+ }
+}
+
+void Queue::requeue(const QueuedMessage& msg){
+ if (policy.get() && !policy->isEnqueued(msg)) return;
+
+ QueueListeners::NotificationSet copy;
+ {
+ Mutex::ScopedLock locker(messageLock);
+ msg.payload->enqueueComplete(); // mark the message as enqueued
+ messages.push_front(msg);
+ listeners.populate(copy);
+ }
+ copy.notify();
+}
+
+void Queue::clearLVQIndex(const QueuedMessage& msg){
+ if (lastValueQueue){
+ const framing::FieldTable* ft = msg.payload->getApplicationHeaders();
+ string key = ft->getAsString(qpidVQMatchProperty);
+ lvq.erase(key);
+ }
+}
+
+bool Queue::acquire(const QueuedMessage& msg) {
+ Mutex::ScopedLock locker(messageLock);
+ QPID_LOG(debug, "attempting to acquire " << msg.position);
+ for (Messages::iterator i = messages.begin(); i != messages.end(); i++) {
+ if ((i->position == msg.position && !lastValueQueue) // note that in some cases payload not be set
+ || (lastValueQueue && (i->position == msg.position) &&
+ msg.payload.get() == checkLvqReplace(*i).payload.get()) ) {
+
+ clearLVQIndex(msg);
+ messages.erase(i);
+ QPID_LOG(debug, "Match found, acquire succeeded: " << i->position << " == " << msg.position);
+ return true;
+ } else {
+ QPID_LOG(debug, "No match: " << i->position << " != " << msg.position);
+ }
+ }
+ QPID_LOG(debug, "Acquire failed for " << msg.position);
+ return false;
+}
+
+bool Queue::getNextMessage(QueuedMessage& m, Consumer::shared_ptr c)
+{
+ if (c->preAcquires()) {
+ return consumeNextMessage(m, c);
+ } else {
+ return browseNextMessage(m, c);
+ }
+}
+
+bool Queue::checkForMessages(Consumer::shared_ptr c)
+{
+ Mutex::ScopedLock locker(messageLock);
+ if (messages.empty()) {
+ //no message available, register consumer for notification
+ //when this changes
+ listeners.addListener(c);
+ return false;
+ } else {
+ QueuedMessage msg = getFront();
+ if (store && !msg.payload->isEnqueueComplete()) {
+ //though a message is on the queue, it has not yet been
+ //enqueued and so is not available for consumption yet,
+ //register consumer for notification when this changes
+ listeners.addListener(c);
+ return false;
+ } else {
+ //check that consumer has sufficient credit for the
+ //message (if it does not, no need to register it for
+ //notification as the consumer itself will handle the
+ //credit allocation required to change this condition).
+ return c->accept(msg.payload);
+ }
+ }
+}
+
+bool Queue::consumeNextMessage(QueuedMessage& m, Consumer::shared_ptr c)
+{
+ while (true) {
+ Mutex::ScopedLock locker(messageLock);
+ if (messages.empty()) {
+ QPID_LOG(debug, "No messages to dispatch on queue '" << name << "'");
+ listeners.addListener(c);
+ return false;
+ } else {
+ QueuedMessage msg = getFront();
+ if (msg.payload->hasExpired()) {
+ QPID_LOG(debug, "Message expired from queue '" << name << "'");
+ popAndDequeue();
+ continue;
+ }
+
+ if (c->filter(msg.payload)) {
+ if (c->accept(msg.payload)) {
+ m = msg;
+ popMsg(msg);
+ return true;
+ } else {
+ //message(s) are available but consumer hasn't got enough credit
+ QPID_LOG(debug, "Consumer can't currently accept message from '" << name << "'");
+ return false;
+ }
+ } else {
+ //consumer will never want this message
+ QPID_LOG(debug, "Consumer doesn't want message from '" << name << "'");
+ return false;
+ }
+ }
+ }
+}
+
+
+bool Queue::browseNextMessage(QueuedMessage& m, Consumer::shared_ptr c)
+{
+ QueuedMessage msg(this);
+ while (seek(msg, c)) {
+ if (c->filter(msg.payload) && !msg.payload->hasExpired()) {
+ if (c->accept(msg.payload)) {
+ //consumer wants the message
+ c->position = msg.position;
+ m = msg;
+ if (!lastValueQueueNoBrowse) clearLVQIndex(msg);
+ if (lastValueQueue) {
+ boost::intrusive_ptr<Message> replacement = msg.payload->getReplacementMessage(this);
+ if (replacement.get()) m.payload = replacement;
+ }
+ return true;
+ } else {
+ //browser hasn't got enough credit for the message
+ QPID_LOG(debug, "Browser can't currently accept message from '" << name << "'");
+ return false;
+ }
+ } else {
+ //consumer will never want this message, continue seeking
+ c->position = msg.position;
+ QPID_LOG(debug, "Browser skipping message from '" << name << "'");
+ }
+ }
+ return false;
+}
+
+void Queue::removeListener(Consumer::shared_ptr c)
+{
+ QueueListeners::NotificationSet set;
+ {
+ Mutex::ScopedLock locker(messageLock);
+ listeners.removeListener(c);
+ if (messages.size()) {
+ listeners.populate(set);
+ }
+ }
+ set.notify();
+}
+
+bool Queue::dispatch(Consumer::shared_ptr c)
+{
+ QueuedMessage msg(this);
+ if (getNextMessage(msg, c)) {
+ c->deliver(msg);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool Queue::seek(QueuedMessage& msg, Consumer::shared_ptr c) {
+ Mutex::ScopedLock locker(messageLock);
+ if (!messages.empty() && messages.back().position > c->position) {
+ if (c->position < getFront().position) {
+ msg = getFront();
+ return true;
+ } else {
+ //TODO: can improve performance of this search, for now just searching linearly from end
+ Messages::reverse_iterator pos;
+ for (Messages::reverse_iterator i = messages.rbegin(); i != messages.rend() && i->position > c->position; i++) {
+ pos = i;
+ }
+ msg = *pos;
+ return true;
+ }
+ }
+ listeners.addListener(c);
+ return false;
+}
+
+namespace {
+struct PositionEquals {
+ SequenceNumber pos;
+ PositionEquals(SequenceNumber p) : pos(p) {}
+ bool operator()(const QueuedMessage& msg) const { return msg.position == pos; }
+};
+}// namespace
+
+QueuedMessage Queue::find(SequenceNumber pos) const {
+ Mutex::ScopedLock locker(messageLock);
+ Messages::const_iterator i = std::find_if(messages.begin(), messages.end(), PositionEquals(pos));
+ if (i != messages.end())
+ return *i;
+ return QueuedMessage();
+}
+
+void Queue::consume(Consumer::shared_ptr c, bool requestExclusive){
+ Mutex::ScopedLock locker(consumerLock);
+ if(exclusive) {
+ throw ResourceLockedException(
+ QPID_MSG("Queue " << getName() << " has an exclusive consumer. No more consumers allowed."));
+ } else if(requestExclusive) {
+ if(consumerCount) {
+ throw ResourceLockedException(
+ QPID_MSG("Queue " << getName() << " already has consumers. Exclusive access denied."));
+ } else {
+ exclusive = c->getSession();
+ }
+ }
+ consumerCount++;
+ if (mgmtObject != 0)
+ mgmtObject->inc_consumerCount ();
+}
+
+void Queue::cancel(Consumer::shared_ptr c){
+ removeListener(c);
+ Mutex::ScopedLock locker(consumerLock);
+ consumerCount--;
+ if(exclusive) exclusive = 0;
+ if (mgmtObject != 0)
+ mgmtObject->dec_consumerCount ();
+}
+
+QueuedMessage Queue::get(){
+ Mutex::ScopedLock locker(messageLock);
+ QueuedMessage msg(this);
+
+ if(!messages.empty()){
+ msg = getFront();
+ popMsg(msg);
+ }
+ return msg;
+}
+
+void Queue::purgeExpired()
+{
+ //As expired messages are discarded during dequeue also, only
+ //bother explicitly expiring if the rate of dequeues since last
+ //attempt is less than one per second.
+ if (dequeueTracker.sampleRatePerSecond() < 1) {
+ Messages expired;
+ {
+ Mutex::ScopedLock locker(messageLock);
+ for (Messages::iterator i = messages.begin(); i != messages.end();) {
+ if (lastValueQueue) checkLvqReplace(*i);
+ if (i->payload->hasExpired()) {
+ expired.push_back(*i);
+ i = messages.erase(i);
+ } else {
+ ++i;
+ }
+ }
+ }
+ for_each(expired.begin(), expired.end(), bind(&Queue::dequeue, this, (TransactionContext*) 0, _1));
+ }
+}
+
+/**
+ * purge - for purging all or some messages on a queue
+ * depending on the purge_request
+ *
+ * purge_request == 0 then purge all messages
+ * == N then purge N messages from queue
+ * Sometimes purge_request == 1 to unblock the top of queue
+ */
+uint32_t Queue::purge(const uint32_t purge_request){
+ Mutex::ScopedLock locker(messageLock);
+ uint32_t purge_count = purge_request; // only comes into play if >0
+
+ uint32_t count = 0;
+ // Either purge them all or just the some (purge_count) while the queue isn't empty.
+ while((!purge_request || purge_count--) && !messages.empty()) {
+ popAndDequeue();
+ count++;
+ }
+ return count;
+}
+
+uint32_t Queue::move(const Queue::shared_ptr destq, uint32_t qty) {
+ Mutex::ScopedLock locker(messageLock);
+ uint32_t move_count = qty; // only comes into play if qty >0
+ uint32_t count = 0; // count how many were moved for returning
+
+ while((!qty || move_count--) && !messages.empty()) {
+ QueuedMessage qmsg = getFront();
+ boost::intrusive_ptr<Message> msg = qmsg.payload;
+ destq->deliver(msg); // deliver message to the destination queue
+ popMsg(qmsg);
+ dequeue(0, qmsg);
+ count++;
+ }
+ return count;
+}
+
+void Queue::popMsg(QueuedMessage& qmsg)
+{
+ if (lastValueQueue){
+ const framing::FieldTable* ft = qmsg.payload->getApplicationHeaders();
+ string key = ft->getAsString(qpidVQMatchProperty);
+ lvq.erase(key);
+ }
+ messages.pop_front();
+ ++dequeueTracker;
+}
+
+void Queue::push(boost::intrusive_ptr<Message>& msg){
+ QueueListeners::NotificationSet copy;
+ {
+ Mutex::ScopedLock locker(messageLock);
+ QueuedMessage qm(this, msg, ++sequence);
+ if (policy.get()) policy->tryEnqueue(qm);
+
+ LVQ::iterator i;
+ if (lastValueQueue){
+ const framing::FieldTable* ft = msg->getApplicationHeaders();
+ string key = ft->getAsString(qpidVQMatchProperty);
+
+ i = lvq.find(key);
+ if (i == lvq.end()){
+ messages.push_back(qm);
+ listeners.populate(copy);
+ lvq[key] = msg;
+ }else {
+ i->second->setReplacementMessage(msg,this);
+ qm.payload = i->second;
+ dequeued(qm);
+ }
+ }else {
+ messages.push_back(qm);
+ listeners.populate(copy);
+ }
+ }
+ copy.notify();
+}
+
+QueuedMessage Queue::getFront()
+{
+ QueuedMessage msg = messages.front();
+ if (lastValueQueue) {
+ boost::intrusive_ptr<Message> replacement = msg.payload->getReplacementMessage(this);
+ if (replacement.get()) msg.payload = replacement;
+ }
+ return msg;
+}
+
+QueuedMessage& Queue::checkLvqReplace(QueuedMessage& msg) const
+{
+ boost::intrusive_ptr<Message> replacement = msg.payload->getReplacementMessage(this);
+ if (replacement.get()) msg.payload = replacement;
+ return msg;
+}
+
+/** function only provided for unit tests, or code not in critical message path */
+uint32_t Queue::getMessageCount() const
+{
+ Mutex::ScopedLock locker(messageLock);
+
+ uint32_t count = 0;
+ for ( Messages::const_iterator i = messages.begin(); i != messages.end(); ++i ) {
+ //NOTE: don't need to use checkLvqReplace() here as it
+ //is only relevant for LVQ which does not support persistence
+ //so the enqueueComplete check has no effect
+ if ( i->payload->isEnqueueComplete() ) count ++;
+ }
+
+ return count;
+}
+
+uint32_t Queue::getConsumerCount() const
+{
+ Mutex::ScopedLock locker(consumerLock);
+ return consumerCount;
+}
+
+bool Queue::canAutoDelete() const
+{
+ Mutex::ScopedLock locker(consumerLock);
+ return autodelete && !consumerCount;
+}
+
+void Queue::clearLastNodeFailure()
+{
+ inLastNodeFailure = false;
+}
+
+void Queue::setLastNodeFailure()
+{
+ if (persistLastNode){
+ Mutex::ScopedLock locker(messageLock);
+ for ( Messages::iterator i = messages.begin(); i != messages.end(); ++i ) {
+ if (lastValueQueue) checkLvqReplace(*i);
+ i->payload->forcePersistent();
+ if (i->payload->getPersistenceId() == 0){
+ enqueue(0, i->payload);
+ }
+ }
+ inLastNodeFailure = true;
+ }
+}
+
+// return true if store exists,
+bool Queue::enqueue(TransactionContext* ctxt, boost::intrusive_ptr<Message> msg)
+{
+ if (inLastNodeFailure && persistLastNode){
+ msg->forcePersistent();
+ }
+
+ if (traceId.size()) {
+ msg->addTraceId(traceId);
+ }
+
+ if (msg->isPersistent() && store && !lastValueQueue) {
+ msg->enqueueAsync(shared_from_this(), store); //increment to async counter -- for message sent to more than one queue
+ boost::intrusive_ptr<PersistableMessage> pmsg = boost::static_pointer_cast<PersistableMessage>(msg);
+ store->enqueue(ctxt, pmsg, *this);
+ return true;
+ }
+ return false;
+}
+
+// return true if store exists,
+bool Queue::dequeue(TransactionContext* ctxt, const QueuedMessage& msg)
+{
+ if (policy.get() && !policy->isEnqueued(msg)) return false;
+ {
+ Mutex::ScopedLock locker(messageLock);
+ if (!ctxt) {
+ dequeued(msg);
+ }
+ }
+ if (msg.payload->isPersistent() && store && !lastValueQueue) {
+ msg.payload->dequeueAsync(shared_from_this(), store); //increment to async counter -- for message sent to more than one queue
+ boost::intrusive_ptr<PersistableMessage> pmsg = boost::static_pointer_cast<PersistableMessage>(msg.payload);
+ store->dequeue(ctxt, pmsg, *this);
+ return true;
+ }
+ return false;
+}
+
+void Queue::dequeueCommitted(const QueuedMessage& msg)
+{
+ Mutex::ScopedLock locker(messageLock);
+ dequeued(msg);
+ if (mgmtObject != 0) {
+ mgmtObject->inc_msgTxnDequeues();
+ mgmtObject->inc_byteTxnDequeues(msg.payload->contentSize());
+ }
+}
+
+/**
+ * Removes a message from the in-memory delivery queue as well
+ * dequeing it from the logical (and persistent if applicable) queue
+ */
+void Queue::popAndDequeue()
+{
+ QueuedMessage msg = getFront();
+ popMsg(msg);
+ dequeue(0, msg);
+}
+
+/**
+ * Updates policy and management when a message has been dequeued,
+ * expects messageLock to be held
+ */
+void Queue::dequeued(const QueuedMessage& msg)
+{
+ if (policy.get()) policy->dequeued(msg);
+ mgntDeqStats(msg.payload);
+}
+
+
+void Queue::create(const FieldTable& _settings)
+{
+ settings = _settings;
+ if (store) {
+ store->create(*this, _settings);
+ }
+ configure(_settings);
+}
+
+void Queue::configure(const FieldTable& _settings)
+{
+ setPolicy(QueuePolicy::createQueuePolicy(_settings));
+ //set this regardless of owner to allow use of no-local with exclusive consumers also
+ noLocal = _settings.get(qpidNoLocal);
+ QPID_LOG(debug, "Configured queue with no-local=" << noLocal);
+
+ lastValueQueue= _settings.get(qpidLastValueQueue);
+ if (lastValueQueue) QPID_LOG(debug, "Configured queue as Last Value Queue");
+
+ lastValueQueueNoBrowse = _settings.get(qpidLastValueQueueNoBrowse);
+ if (lastValueQueueNoBrowse){
+ QPID_LOG(debug, "Configured queue as Last Value Queue No Browse");
+ lastValueQueue = lastValueQueueNoBrowse;
+ }
+
+ persistLastNode= _settings.get(qpidPersistLastNode);
+ if (persistLastNode) QPID_LOG(debug, "Configured queue to Persist data if cluster fails to one node");
+
+ traceId = _settings.getAsString(qpidTraceIdentity);
+ std::string excludeList = _settings.getAsString(qpidTraceExclude);
+ if (excludeList.size()) {
+ split(traceExclude, excludeList, ", ");
+ }
+ QPID_LOG(debug, "Configured queue " << getName() << " with qpid.trace.id='" << traceId
+ << "' and qpid.trace.exclude='"<< excludeList << "' i.e. " << traceExclude.size() << " elements");
+
+ if (mgmtObject != 0)
+ mgmtObject->set_arguments (_settings);
+}
+
+void Queue::destroy()
+{
+ if (alternateExchange.get()) {
+ Mutex::ScopedLock locker(messageLock);
+ while(!messages.empty()){
+ DeliverableMessage msg(getFront().payload);
+ alternateExchange->route(msg, msg.getMessage().getRoutingKey(),
+ msg.getMessage().getApplicationHeaders());
+ popAndDequeue();
+ }
+ alternateExchange->decAlternateUsers();
+ }
+
+ if (store) {
+ store->flush(*this);
+ store->destroy(*this);
+ store = 0;//ensure we make no more calls to the store for this queue
+ }
+}
+
+void Queue::bound(const string& exchange, const string& key,
+ const FieldTable& args)
+{
+ bindings.add(exchange, key, args);
+}
+
+void Queue::unbind(ExchangeRegistry& exchanges, Queue::shared_ptr shared_ref)
+{
+ bindings.unbind(exchanges, shared_ref);
+}
+
+void Queue::setPolicy(std::auto_ptr<QueuePolicy> _policy)
+{
+ policy = _policy;
+}
+
+const QueuePolicy* Queue::getPolicy()
+{
+ return policy.get();
+}
+
+uint64_t Queue::getPersistenceId() const
+{
+ return persistenceId;
+}
+
+void Queue::setPersistenceId(uint64_t _persistenceId) const
+{
+ if (mgmtObject != 0 && persistenceId == 0)
+ {
+ ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+ agent->addObject (mgmtObject, 0x3000000000000000LL + _persistenceId);
+
+ if (externalQueueStore) {
+ ManagementObject* childObj = externalQueueStore->GetManagementObject();
+ if (childObj != 0)
+ childObj->setReference(mgmtObject->getObjectId());
+ }
+ }
+ persistenceId = _persistenceId;
+}
+
+void Queue::encode(Buffer& buffer) const
+{
+ buffer.putShortString(name);
+ buffer.put(settings);
+ if (policy.get()) {
+ buffer.put(*policy);
+ }
+}
+
+uint32_t Queue::encodedSize() const
+{
+ return name.size() + 1/*short string size octet*/ + settings.encodedSize()
+ + (policy.get() ? (*policy).encodedSize() : 0);
+}
+
+Queue::shared_ptr Queue::decode(QueueRegistry& queues, Buffer& buffer)
+{
+ string name;
+ buffer.getShortString(name);
+ std::pair<Queue::shared_ptr, bool> result = queues.declare(name, true);
+ buffer.get(result.first->settings);
+ result.first->configure(result.first->settings);
+ if (result.first->policy.get() && buffer.available() >= result.first->policy->encodedSize()) {
+ buffer.get ( *(result.first->policy) );
+ }
+ return result.first;
+}
+
+
+void Queue::setAlternateExchange(boost::shared_ptr<Exchange> exchange)
+{
+ alternateExchange = exchange;
+}
+
+boost::shared_ptr<Exchange> Queue::getAlternateExchange()
+{
+ return alternateExchange;
+}
+
+void Queue::tryAutoDelete(Broker& broker, Queue::shared_ptr queue)
+{
+ if (broker.getQueues().destroyIf(queue->getName(),
+ boost::bind(boost::mem_fn(&Queue::canAutoDelete), queue))) {
+ queue->unbind(broker.getExchanges(), queue);
+ queue->destroy();
+ }
+}
+
+bool Queue::isExclusiveOwner(const OwnershipToken* const o) const
+{
+ Mutex::ScopedLock locker(ownershipLock);
+ return o == owner;
+}
+
+void Queue::releaseExclusiveOwnership()
+{
+ Mutex::ScopedLock locker(ownershipLock);
+ owner = 0;
+}
+
+bool Queue::setExclusiveOwner(const OwnershipToken* const o)
+{
+ Mutex::ScopedLock locker(ownershipLock);
+ if (owner) {
+ return false;
+ } else {
+ owner = o;
+ return true;
+ }
+}
+
+bool Queue::hasExclusiveOwner() const
+{
+ Mutex::ScopedLock locker(ownershipLock);
+ return owner != 0;
+}
+
+bool Queue::hasExclusiveConsumer() const
+{
+ return exclusive;
+}
+
+void Queue::setExternalQueueStore(ExternalQueueStore* inst) {
+ if (externalQueueStore!=inst && externalQueueStore)
+ delete externalQueueStore;
+ externalQueueStore = inst;
+
+ if (inst) {
+ ManagementObject* childObj = inst->GetManagementObject();
+ if (childObj != 0 && mgmtObject != 0)
+ childObj->setReference(mgmtObject->getObjectId());
+ }
+}
+
+bool Queue::releaseMessageContent(const QueuedMessage& m)
+{
+ if (store && !NullMessageStore::isNullStore(store)) {
+ QPID_LOG(debug, "Message " << m.position << " on " << name << " released from memory");
+ m.payload->releaseContent(store);
+ return true;
+ } else {
+ QPID_LOG(warning, "Message " << m.position << " on " << name
+ << " cannot be released from memory as the queue is not durable");
+ return false;
+ }
+}
+
+ManagementObject* Queue::GetManagementObject (void) const
+{
+ return (ManagementObject*) mgmtObject;
+}
+
+Manageable::status_t Queue::ManagementMethod (uint32_t methodId, Args& args, string&)
+{
+ Manageable::status_t status = Manageable::STATUS_UNKNOWN_METHOD;
+
+ QPID_LOG (debug, "Queue::ManagementMethod [id=" << methodId << "]");
+
+ switch (methodId)
+ {
+ case _qmf::Queue::METHOD_PURGE :
+ _qmf::ArgsQueuePurge& iargs = (_qmf::ArgsQueuePurge&) args;
+ purge (iargs.i_request);
+ status = Manageable::STATUS_OK;
+ break;
+ }
+
+ return status;
+}
+
+void Queue::setPosition(SequenceNumber n) {
+ Mutex::ScopedLock locker(messageLock);
+ sequence = n;
+}
diff --git a/RC9/qpid/cpp/src/qpid/broker/Queue.h b/RC9/qpid/cpp/src/qpid/broker/Queue.h
new file mode 100644
index 0000000000..e0bcc25fa3
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/Queue.h
@@ -0,0 +1,287 @@
+#ifndef _broker_Queue_h
+#define _broker_Queue_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "OwnershipToken.h"
+#include "Consumer.h"
+#include "Message.h"
+#include "PersistableQueue.h"
+#include "QueuePolicy.h"
+#include "QueueBindings.h"
+#include "QueueListeners.h"
+#include "RateTracker.h"
+
+#include "qpid/framing/FieldTable.h"
+#include "qpid/sys/Monitor.h"
+#include "qpid/management/Manageable.h"
+#include "qmf/org/apache/qpid/broker/Queue.h"
+#include "qpid/framing/amqp_types.h"
+
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/intrusive_ptr.hpp>
+
+#include <list>
+#include <vector>
+#include <memory>
+#include <deque>
+#include <algorithm>
+
+namespace qpid {
+ namespace broker {
+ class Broker;
+ class MessageStore;
+ class QueueRegistry;
+ class TransactionContext;
+ class Exchange;
+
+ using std::string;
+
+ /**
+ * The brokers representation of an amqp queue. Messages are
+ * delivered to a queue from where they can be dispatched to
+ * registered consumers or be stored until dequeued or until one
+ * or more consumers registers.
+ */
+ class Queue : public boost::enable_shared_from_this<Queue>,
+ public PersistableQueue, public management::Manageable {
+
+ typedef std::deque<QueuedMessage> Messages;
+ typedef std::map<string,boost::intrusive_ptr<Message> > LVQ;
+
+ const string name;
+ const bool autodelete;
+ MessageStore* store;
+ const OwnershipToken* owner;
+ uint32_t consumerCount;
+ OwnershipToken* exclusive;
+ bool noLocal;
+ bool lastValueQueue;
+ bool lastValueQueueNoBrowse;
+ bool persistLastNode;
+ bool inLastNodeFailure;
+ std::string traceId;
+ std::vector<std::string> traceExclude;
+ QueueListeners listeners;
+ Messages messages;
+ LVQ lvq;
+ mutable qpid::sys::Mutex consumerLock;
+ mutable qpid::sys::Mutex messageLock;
+ mutable qpid::sys::Mutex ownershipLock;
+ mutable uint64_t persistenceId;
+ framing::FieldTable settings;
+ std::auto_ptr<QueuePolicy> policy;
+ bool policyExceeded;
+ QueueBindings bindings;
+ boost::shared_ptr<Exchange> alternateExchange;
+ framing::SequenceNumber sequence;
+ qmf::org::apache::qpid::broker::Queue* mgmtObject;
+ RateTracker dequeueTracker;
+
+ void push(boost::intrusive_ptr<Message>& msg);
+ void setPolicy(std::auto_ptr<QueuePolicy> policy);
+ bool seek(QueuedMessage& msg, Consumer::shared_ptr position);
+ bool getNextMessage(QueuedMessage& msg, Consumer::shared_ptr c);
+ bool consumeNextMessage(QueuedMessage& msg, Consumer::shared_ptr c);
+ bool browseNextMessage(QueuedMessage& msg, Consumer::shared_ptr c);
+
+ void removeListener(Consumer::shared_ptr);
+
+ bool isExcluded(boost::intrusive_ptr<Message>& msg);
+
+ void dequeued(const QueuedMessage& msg);
+ void popAndDequeue();
+ QueuedMessage getFront();
+ QueuedMessage& checkLvqReplace(QueuedMessage& msg) const;
+ void clearLVQIndex(const QueuedMessage& msg);
+
+ inline void mgntEnqStats(const boost::intrusive_ptr<Message>& msg)
+ {
+ if (mgmtObject != 0) {
+ mgmtObject->inc_msgTotalEnqueues ();
+ mgmtObject->inc_byteTotalEnqueues (msg->contentSize ());
+ if (msg->isPersistent ()) {
+ mgmtObject->inc_msgPersistEnqueues ();
+ mgmtObject->inc_bytePersistEnqueues (msg->contentSize ());
+ }
+ }
+ }
+ inline void mgntDeqStats(const boost::intrusive_ptr<Message>& msg)
+ {
+ if (mgmtObject != 0){
+ mgmtObject->inc_msgTotalDequeues ();
+ mgmtObject->inc_byteTotalDequeues (msg->contentSize());
+ if (msg->isPersistent ()){
+ mgmtObject->inc_msgPersistDequeues ();
+ mgmtObject->inc_bytePersistDequeues (msg->contentSize());
+ }
+ }
+ }
+
+ public:
+
+ virtual void notifyDurableIOComplete();
+ typedef boost::shared_ptr<Queue> shared_ptr;
+
+ typedef std::vector<shared_ptr> vector;
+
+ Queue(const string& name, bool autodelete = false,
+ MessageStore* const store = 0,
+ const OwnershipToken* const owner = 0,
+ management::Manageable* parent = 0);
+ ~Queue();
+
+ bool dispatch(Consumer::shared_ptr);
+ /**
+ * Check whether there would be a message available for
+ * dispatch to this consumer. If not, the consumer will be
+ * notified of events that may have changed this
+ * situation.
+ */
+ bool checkForMessages(Consumer::shared_ptr);
+
+ void create(const qpid::framing::FieldTable& settings);
+ void configure(const qpid::framing::FieldTable& settings);
+ void destroy();
+ void bound(const string& exchange, const string& key, const qpid::framing::FieldTable& args);
+ void unbind(ExchangeRegistry& exchanges, Queue::shared_ptr shared_ref);
+
+ bool acquire(const QueuedMessage& msg);
+
+ /**
+ * Delivers a message to the queue. Will record it as
+ * enqueued if persistent then process it.
+ */
+ void deliver(boost::intrusive_ptr<Message>& msg);
+ /**
+ * Dispatches the messages immediately to a consumer if
+ * one is available or stores it for later if not.
+ */
+ void process(boost::intrusive_ptr<Message>& msg);
+ /**
+ * Returns a message to the in-memory queue (due to lack
+ * of acknowledegement from a receiver). If a consumer is
+ * available it will be dispatched immediately, else it
+ * will be returned to the front of the queue.
+ */
+ void requeue(const QueuedMessage& msg);
+ /**
+ * Used during recovery to add stored messages back to the queue
+ */
+ void recover(boost::intrusive_ptr<Message>& msg);
+
+ void consume(Consumer::shared_ptr c, bool exclusive = false);
+ void cancel(Consumer::shared_ptr c);
+
+ uint32_t purge(const uint32_t purge_request = 0); //defaults to all messages
+ void purgeExpired();
+
+ //move qty # of messages to destination Queue destq
+ uint32_t move(const Queue::shared_ptr destq, uint32_t qty);
+
+ uint32_t getMessageCount() const;
+ uint32_t getConsumerCount() const;
+ inline const string& getName() const { return name; }
+ bool isExclusiveOwner(const OwnershipToken* const o) const;
+ void releaseExclusiveOwnership();
+ bool setExclusiveOwner(const OwnershipToken* const o);
+ bool hasExclusiveConsumer() const;
+ bool hasExclusiveOwner() const;
+ inline bool isDurable() const { return store != 0; }
+ inline const framing::FieldTable& getSettings() const { return settings; }
+ inline bool isAutoDelete() const { return autodelete; }
+ bool canAutoDelete() const;
+ const QueueBindings& getBindings() const { return bindings; }
+
+ /**
+ * used to take messages from in memory and flush down to disk.
+ */
+ void setLastNodeFailure();
+ void clearLastNodeFailure();
+
+ bool enqueue(TransactionContext* ctxt, boost::intrusive_ptr<Message> msg);
+ /**
+ * dequeue from store (only done once messages is acknowledged)
+ */
+ bool dequeue(TransactionContext* ctxt, const QueuedMessage &msg);
+ /**
+ * Inform the queue that a previous transactional dequeue
+ * committed.
+ */
+ void dequeueCommitted(const QueuedMessage& msg);
+
+ /**
+ * Gets the next available message
+ */
+ QueuedMessage get();
+
+ /** Get the message at position pos */
+ QueuedMessage find(framing::SequenceNumber pos) const;
+
+ const QueuePolicy* getPolicy();
+
+ void setAlternateExchange(boost::shared_ptr<Exchange> exchange);
+ boost::shared_ptr<Exchange> getAlternateExchange();
+ bool isLocal(boost::intrusive_ptr<Message>& msg);
+
+ //PersistableQueue support:
+ uint64_t getPersistenceId() const;
+ void setPersistenceId(uint64_t persistenceId) const;
+ void encode(framing::Buffer& buffer) const;
+ uint32_t encodedSize() const;
+
+ static Queue::shared_ptr decode(QueueRegistry& queues, framing::Buffer& buffer);
+ static void tryAutoDelete(Broker& broker, Queue::shared_ptr);
+
+ virtual void setExternalQueueStore(ExternalQueueStore* inst);
+
+ // Manageable entry points
+ management::ManagementObject* GetManagementObject (void) const;
+ management::Manageable::status_t
+ ManagementMethod (uint32_t methodId, management::Args& args, std::string& text);
+
+ /** Apply f to each Message on the queue. */
+ template <class F> void eachMessage(F f) const {
+ sys::Mutex::ScopedLock l(messageLock);
+ std::for_each(messages.begin(), messages.end(), f);
+ }
+
+ /** Apply f to each QueueBinding on the queue */
+ template <class F> void eachBinding(F f) {
+ bindings.eachBinding(f);
+ }
+
+ bool releaseMessageContent(const QueuedMessage&);
+
+ void popMsg(QueuedMessage& qmsg);
+
+ /** Set the position sequence number for the next message on the queue.
+ * Must be >= the current sequence number.
+ * Used by cluster to replicate queues.
+ */
+ void setPosition(framing::SequenceNumber pos);
+ };
+ }
+}
+
+
+#endif /*!_broker_Queue_h*/
diff --git a/RC9/qpid/cpp/src/qpid/broker/QueueBindings.cpp b/RC9/qpid/cpp/src/qpid/broker/QueueBindings.cpp
new file mode 100644
index 0000000000..6a1fa6aca3
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/QueueBindings.cpp
@@ -0,0 +1,46 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "QueueBindings.h"
+#include "ExchangeRegistry.h"
+#include "qpid/framing/reply_exceptions.h"
+
+using qpid::framing::FieldTable;
+using qpid::framing::NotFoundException;
+using std::string;
+using namespace qpid::broker;
+
+void QueueBindings::add(const string& exchange, const string& key, const FieldTable& args)
+{
+ bindings.push_back(QueueBinding(exchange, key, args));
+}
+
+void QueueBindings::unbind(ExchangeRegistry& exchanges, Queue::shared_ptr queue)
+{
+ for (Bindings::iterator i = bindings.begin(); i != bindings.end(); i++) {
+ try {
+ exchanges.get(i->exchange)->unbind(queue, i->key, &(i->args));
+ } catch (const NotFoundException&) {}
+ }
+}
+
+QueueBinding::QueueBinding(const string& _exchange, const string& _key, const FieldTable& _args)
+ : exchange(_exchange), key(_key), args(_args)
+{}
diff --git a/RC9/qpid/cpp/src/qpid/broker/QueueBindings.h b/RC9/qpid/cpp/src/qpid/broker/QueueBindings.h
new file mode 100644
index 0000000000..1b90ba5540
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/QueueBindings.h
@@ -0,0 +1,61 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _QueueBindings_
+#define _QueueBindings_
+
+#include "qpid/framing/FieldTable.h"
+#include <boost/ptr_container/ptr_list.hpp>
+#include <boost/shared_ptr.hpp>
+#include <algorithm>
+
+namespace qpid {
+namespace broker {
+
+class ExchangeRegistry;
+class Queue;
+
+struct QueueBinding{
+ std::string exchange;
+ std::string key;
+ qpid::framing::FieldTable args;
+ QueueBinding(const std::string& exchange, const std::string& key, const qpid::framing::FieldTable& args);
+};
+
+class QueueBindings
+{
+ public:
+
+ /** Apply f to each QueueBinding. */
+ template <class F> void eachBinding(F f) const { std::for_each(bindings.begin(), bindings.end(), f); }
+
+ void add(const std::string& exchange, const std::string& key, const qpid::framing::FieldTable& args);
+ void unbind(ExchangeRegistry& exchanges, boost::shared_ptr<Queue> queue);
+
+ private:
+ typedef std::vector<QueueBinding> Bindings;
+ Bindings bindings;
+};
+
+
+}} // namespace qpid::broker
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/QueueCleaner.cpp b/RC9/qpid/cpp/src/qpid/broker/QueueCleaner.cpp
new file mode 100644
index 0000000000..0774dce2b7
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/QueueCleaner.cpp
@@ -0,0 +1,52 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "QueueCleaner.h"
+
+#include "Broker.h"
+#include <boost/bind.hpp>
+
+namespace qpid {
+namespace broker {
+
+QueueCleaner::QueueCleaner(QueueRegistry& q, Timer& t) : queues(q), timer(t) {}
+
+void QueueCleaner::start(qpid::sys::Duration p)
+{
+ task = boost::intrusive_ptr<TimerTask>(new Task(*this, p));
+ timer.add(task);
+}
+
+QueueCleaner::Task::Task(QueueCleaner& p, qpid::sys::Duration d) : TimerTask(d), parent(p) {}
+
+void QueueCleaner::Task::fire()
+{
+ parent.fired();
+}
+
+void QueueCleaner::fired()
+{
+ queues.eachQueue(boost::bind(&Queue::purgeExpired, _1));
+ task->reset();
+ timer.add(task);
+}
+
+
+}} // namespace qpid::broker
diff --git a/RC9/qpid/cpp/src/qpid/broker/QueueCleaner.h b/RC9/qpid/cpp/src/qpid/broker/QueueCleaner.h
new file mode 100644
index 0000000000..7903266f5f
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/QueueCleaner.h
@@ -0,0 +1,57 @@
+#ifndef QPID_BROKER_QUEUECLEANER_H
+#define QPID_BROKER_QUEUECLEANER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Timer.h"
+
+namespace qpid {
+namespace broker {
+
+class QueueRegistry;
+/**
+ * TimerTask to purge expired messages from queues
+ */
+class QueueCleaner
+{
+ public:
+ QueueCleaner(QueueRegistry& queues, Timer& timer);
+ void start(qpid::sys::Duration period);
+ private:
+ class Task : public TimerTask
+ {
+ public:
+ Task(QueueCleaner& parent, qpid::sys::Duration duration);
+ void fire();
+ private:
+ QueueCleaner& parent;
+ };
+
+ boost::intrusive_ptr<TimerTask> task;
+ QueueRegistry& queues;
+ Timer& timer;
+
+ void fired();
+};
+}} // namespace qpid::broker
+
+#endif /*!QPID_BROKER_QUEUECLEANER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/broker/QueueListeners.cpp b/RC9/qpid/cpp/src/qpid/broker/QueueListeners.cpp
new file mode 100644
index 0000000000..7baca7d0f4
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/QueueListeners.cpp
@@ -0,0 +1,73 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "QueueListeners.h"
+#include <boost/bind.hpp>
+
+namespace qpid {
+namespace broker {
+
+void QueueListeners::addListener(Consumer::shared_ptr c)
+{
+ if (c->preAcquires()) {
+ add(consumers, c);
+ } else {
+ add(browsers, c);
+ }
+}
+
+void QueueListeners::removeListener(Consumer::shared_ptr c)
+{
+ if (c->preAcquires()) {
+ remove(consumers, c);
+ } else {
+ remove(browsers, c);
+ }
+}
+
+void QueueListeners::populate(NotificationSet& set)
+{
+ if (consumers.size()) {
+ set.consumer = consumers.front();
+ consumers.pop_front();
+ } else {
+ browsers.swap(set.browsers);
+ }
+}
+
+void QueueListeners::add(Listeners& listeners, Consumer::shared_ptr c)
+{
+ Listeners::iterator i = std::find(listeners.begin(), listeners.end(), c);
+ if (i == listeners.end()) listeners.push_back(c);
+}
+
+void QueueListeners::remove(Listeners& listeners, Consumer::shared_ptr c)
+{
+ Listeners::iterator i = std::find(listeners.begin(), listeners.end(), c);
+ if (i != listeners.end()) listeners.erase(i);
+}
+
+void QueueListeners::NotificationSet::notify()
+{
+ if (consumer) consumer->notify();
+ else for_each(browsers.begin(), browsers.end(), boost::mem_fn(&Consumer::notify));
+}
+
+}} // namespace qpid::broker
diff --git a/RC9/qpid/cpp/src/qpid/broker/QueueListeners.h b/RC9/qpid/cpp/src/qpid/broker/QueueListeners.h
new file mode 100644
index 0000000000..53ed6a17e4
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/QueueListeners.h
@@ -0,0 +1,68 @@
+#ifndef QPID_BROKER_QUEUELISTENERS_H
+#define QPID_BROKER_QUEUELISTENERS_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "Consumer.h"
+#include <list>
+
+namespace qpid {
+namespace broker {
+
+/**
+ * Track and notify components that wish to be notified of messages
+ * that become available on a queue.
+ *
+ * None of the methods defined here are protected by locking. However
+ * the populate method allows a 'snapshot' to be taken of the
+ * listeners to be notified. NotificationSet::notify() may then be
+ * called outside of any lock that protects the QueueListeners
+ * instance from concurrent access.
+ */
+class QueueListeners
+{
+ public:
+ typedef std::list<Consumer::shared_ptr> Listeners;
+
+ class NotificationSet
+ {
+ public:
+ void notify();
+ private:
+ Listeners browsers;
+ Consumer::shared_ptr consumer;
+ friend class QueueListeners;
+ };
+
+ void addListener(Consumer::shared_ptr);
+ void removeListener(Consumer::shared_ptr);
+ void populate(NotificationSet&);
+ private:
+ Listeners consumers;
+ Listeners browsers;
+
+ void add(Listeners&, Consumer::shared_ptr);
+ void remove(Listeners&, Consumer::shared_ptr);
+
+};
+}} // namespace qpid::broker
+
+#endif /*!QPID_BROKER_QUEUELISTENERS_H*/
diff --git a/RC9/qpid/cpp/src/qpid/broker/QueuePolicy.cpp b/RC9/qpid/cpp/src/qpid/broker/QueuePolicy.cpp
new file mode 100644
index 0000000000..41a6709d27
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/QueuePolicy.cpp
@@ -0,0 +1,297 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "QueuePolicy.h"
+#include "Queue.h"
+#include "qpid/Exception.h"
+#include "qpid/framing/FieldValue.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/log/Statement.h"
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+QueuePolicy::QueuePolicy(uint32_t _maxCount, uint64_t _maxSize, const std::string& _type) :
+ maxCount(_maxCount), maxSize(_maxSize), type(_type), count(0), size(0), policyExceeded(false) {}
+
+void QueuePolicy::enqueued(uint64_t _size)
+{
+ if (maxCount) ++count;
+ if (maxSize) size += _size;
+}
+
+void QueuePolicy::dequeued(uint64_t _size)
+{
+ //Note: underflow detection is not reliable in the face of
+ //concurrent updates (at present locking in Queue.cpp prevents
+ //these anyway); updates are atomic and are safe regardless.
+ if (maxCount) {
+ if (count.get() > 0) {
+ --count;
+ } else {
+ throw Exception(QPID_MSG("Attempted count underflow on dequeue(" << _size << "): " << *this));
+ }
+ }
+ if (maxSize) {
+ if (_size > size.get()) {
+ throw Exception(QPID_MSG("Attempted size underflow on dequeue(" << _size << "): " << *this));
+ } else {
+ size -= _size;
+ }
+ }
+}
+
+bool QueuePolicy::checkLimit(const QueuedMessage& m)
+{
+ bool exceeded = (maxSize && (size.get() + m.payload->contentSize()) > maxSize) || (maxCount && (count.get() + 1) > maxCount);
+ if (exceeded) {
+ if (!policyExceeded) {
+ policyExceeded = true;
+ if (m.queue) {
+ QPID_LOG(info, "Queue size exceeded policy for " << m.queue->getName());
+ }
+ }
+ } else {
+ if (policyExceeded) {
+ policyExceeded = false;
+ if (m.queue) {
+ QPID_LOG(info, "Queue size within policy for " << m.queue->getName());
+ }
+ }
+ }
+ return !exceeded;
+}
+
+void QueuePolicy::tryEnqueue(const QueuedMessage& m)
+{
+ if (checkLimit(m)) {
+ enqueued(m);
+ } else {
+ std::string queue = m.queue ? m.queue->getName() : std::string("unknown queue");
+ throw ResourceLimitExceededException(
+ QPID_MSG("Policy exceeded on " << queue << " by message " << m.position
+ << " of size " << m.payload->contentSize() << " , policy: " << *this));
+ }
+}
+
+void QueuePolicy::enqueued(const QueuedMessage& m)
+{
+ enqueued(m.payload->contentSize());
+}
+
+void QueuePolicy::dequeued(const QueuedMessage& m)
+{
+ dequeued(m.payload->contentSize());
+}
+
+bool QueuePolicy::isEnqueued(const QueuedMessage&)
+{
+ return true;
+}
+
+void QueuePolicy::update(FieldTable& settings)
+{
+ if (maxCount) settings.setInt(maxCountKey, maxCount);
+ if (maxSize) settings.setInt(maxSizeKey, maxSize);
+ settings.setString(typeKey, type);
+}
+
+
+int QueuePolicy::getInt(const FieldTable& settings, const std::string& key, int defaultValue)
+{
+ FieldTable::ValuePtr v = settings.get(key);
+ if (v && v->convertsTo<int>()) return v->get<int>();
+ else return defaultValue;
+}
+
+std::string QueuePolicy::getType(const FieldTable& settings)
+{
+ FieldTable::ValuePtr v = settings.get(typeKey);
+ if (v && v->convertsTo<std::string>()) {
+ std::string t = v->get<std::string>();
+ transform(t.begin(), t.end(), t.begin(), tolower);
+ if (t == REJECT || t == FLOW_TO_DISK || t == RING || t == RING_STRICT) return t;
+ }
+ return FLOW_TO_DISK;
+}
+
+void QueuePolicy::setDefaultMaxSize(uint64_t s)
+{
+ defaultMaxSize = s;
+}
+
+
+
+
+
+void QueuePolicy::encode(Buffer& buffer) const
+{
+ buffer.putLong(maxCount);
+ buffer.putLongLong(maxSize);
+ buffer.putLong(count.get());
+ buffer.putLongLong(size.get());
+}
+
+void QueuePolicy::decode ( Buffer& buffer )
+{
+ maxCount = buffer.getLong();
+ maxSize = buffer.getLongLong();
+ count = buffer.getLong();
+ size = buffer.getLongLong();
+}
+
+
+uint32_t QueuePolicy::encodedSize() const {
+ return sizeof(uint32_t) + // maxCount
+ sizeof(uint64_t) + // maxSize
+ sizeof(uint32_t) + // count
+ sizeof(uint64_t); // size
+}
+
+
+
+const std::string QueuePolicy::maxCountKey("qpid.max_count");
+const std::string QueuePolicy::maxSizeKey("qpid.max_size");
+const std::string QueuePolicy::typeKey("qpid.policy_type");
+const std::string QueuePolicy::REJECT("reject");
+const std::string QueuePolicy::FLOW_TO_DISK("flow_to_disk");
+const std::string QueuePolicy::RING("ring");
+const std::string QueuePolicy::RING_STRICT("ring_strict");
+uint64_t QueuePolicy::defaultMaxSize(0);
+
+FlowToDiskPolicy::FlowToDiskPolicy(uint32_t _maxCount, uint64_t _maxSize) :
+ QueuePolicy(_maxCount, _maxSize, FLOW_TO_DISK) {}
+
+bool FlowToDiskPolicy::checkLimit(const QueuedMessage& m)
+{
+ return QueuePolicy::checkLimit(m) || m.queue->releaseMessageContent(m);
+}
+
+RingQueuePolicy::RingQueuePolicy(uint32_t _maxCount, uint64_t _maxSize, const std::string& _type) :
+ QueuePolicy(_maxCount, _maxSize, _type), strict(_type == RING_STRICT) {}
+
+void RingQueuePolicy::enqueued(const QueuedMessage& m)
+{
+ QueuePolicy::enqueued(m);
+ qpid::sys::Mutex::ScopedLock l(lock);
+ queue.push_back(m);
+}
+
+void RingQueuePolicy::dequeued(const QueuedMessage& m)
+{
+ qpid::sys::Mutex::ScopedLock l(lock);
+ QueuePolicy::dequeued(m);
+ //find and remove m from queue
+ for (Messages::iterator i = queue.begin(); i != queue.end() && m.position <= i->position; i++) {
+ if (i->position == m.position) {
+ queue.erase(i);
+ break;
+ }
+ }
+}
+
+bool RingQueuePolicy::isEnqueued(const QueuedMessage& m)
+{
+ qpid::sys::Mutex::ScopedLock l(lock);
+ //for non-strict ring policy, a message can be dequeued before acked; need to detect this
+ for (Messages::iterator i = queue.begin(); i != queue.end() && m.position <= i->position; i++) {
+ if (i->position == m.position) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool RingQueuePolicy::checkLimit(const QueuedMessage& m)
+{
+ if (QueuePolicy::checkLimit(m)) return true;//if haven't hit limit, ok to accept
+
+ QueuedMessage oldest;
+ {
+ qpid::sys::Mutex::ScopedLock l(lock);
+ if (queue.empty()) {
+ QPID_LOG(debug, "Message too large for ring queue "
+ << (m.queue ? m.queue->getName() : std::string("unknown queue"))
+ << " [" << *this << "] "
+ << ": message size = " << m.payload->contentSize() << " bytes");
+ return false;
+ }
+ oldest = queue.front();
+ }
+ if (oldest.queue->acquire(oldest) || !strict) {
+ qpid::sys::Mutex::ScopedLock l(lock);
+ if (oldest.position == queue.front().position) {
+ queue.pop_front();
+ QPID_LOG(debug, "Ring policy triggered in queue "
+ << (m.queue ? m.queue->getName() : std::string("unknown queue"))
+ << ": removed message " << oldest.position << " to make way for " << m.position);
+ }
+ return true;
+ } else {
+ QPID_LOG(debug, "Ring policy could not be triggered in queue "
+ << (m.queue ? m.queue->getName() : std::string("unknown queue"))
+ << ": oldest message (seq-no=" << oldest.position << ") has been delivered but not yet acknowledged or requeued");
+ //in strict mode, if oldest message has been delivered (hence
+ //cannot be acquired) but not yet acked, it should not be
+ //removed and the attempted enqueue should fail
+ return false;
+ }
+}
+
+std::auto_ptr<QueuePolicy> QueuePolicy::createQueuePolicy(const qpid::framing::FieldTable& settings)
+{
+ uint32_t maxCount = getInt(settings, maxCountKey, 0);
+ uint32_t maxSize = getInt(settings, maxSizeKey, defaultMaxSize);
+ if (maxCount || maxSize) {
+ return createQueuePolicy(maxCount, maxSize, getType(settings));
+ } else {
+ return std::auto_ptr<QueuePolicy>();
+ }
+}
+
+std::auto_ptr<QueuePolicy> QueuePolicy::createQueuePolicy(uint32_t maxCount, uint64_t maxSize, const std::string& type)
+{
+ if (type == RING || type == RING_STRICT) {
+ return std::auto_ptr<QueuePolicy>(new RingQueuePolicy(maxCount, maxSize, type));
+ } else if (type == FLOW_TO_DISK) {
+ return std::auto_ptr<QueuePolicy>(new FlowToDiskPolicy(maxCount, maxSize));
+ } else {
+ return std::auto_ptr<QueuePolicy>(new QueuePolicy(maxCount, maxSize, type));
+ }
+
+}
+
+namespace qpid {
+ namespace broker {
+
+std::ostream& operator<<(std::ostream& out, const QueuePolicy& p)
+{
+ if (p.maxSize) out << "size: max=" << p.maxSize << ", current=" << p.size.get();
+ else out << "size: unlimited";
+ out << "; ";
+ if (p.maxCount) out << "count: max=" << p.maxCount << ", current=" << p.count.get();
+ else out << "count: unlimited";
+ out << "; type=" << p.type;
+ return out;
+}
+
+ }
+}
+
diff --git a/RC9/qpid/cpp/src/qpid/broker/QueuePolicy.h b/RC9/qpid/cpp/src/qpid/broker/QueuePolicy.h
new file mode 100644
index 0000000000..0e8c15aa0e
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/QueuePolicy.h
@@ -0,0 +1,109 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _QueuePolicy_
+#define _QueuePolicy_
+
+#include <deque>
+#include <iostream>
+#include <memory>
+#include "QueuedMessage.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/sys/AtomicValue.h"
+#include "qpid/sys/Mutex.h"
+
+namespace qpid {
+namespace broker {
+
+class QueuePolicy
+{
+ static uint64_t defaultMaxSize;
+
+ uint32_t maxCount;
+ uint64_t maxSize;
+ const std::string type;
+ qpid::sys::AtomicValue<uint32_t> count;
+ qpid::sys::AtomicValue<uint64_t> size;
+ bool policyExceeded;
+
+ static int getInt(const qpid::framing::FieldTable& settings, const std::string& key, int defaultValue);
+ static std::string getType(const qpid::framing::FieldTable& settings);
+
+ public:
+ static const std::string maxCountKey;
+ static const std::string maxSizeKey;
+ static const std::string typeKey;
+ static const std::string REJECT;
+ static const std::string FLOW_TO_DISK;
+ static const std::string RING;
+ static const std::string RING_STRICT;
+
+ virtual ~QueuePolicy() {}
+ void tryEnqueue(const QueuedMessage&);
+ virtual void dequeued(const QueuedMessage&);
+ virtual bool isEnqueued(const QueuedMessage&);
+ virtual bool checkLimit(const QueuedMessage&);
+ void update(qpid::framing::FieldTable& settings);
+ uint32_t getMaxCount() const { return maxCount; }
+ uint64_t getMaxSize() const { return maxSize; }
+ void encode(framing::Buffer& buffer) const;
+ void decode ( framing::Buffer& buffer );
+ uint32_t encodedSize() const;
+
+
+ static std::auto_ptr<QueuePolicy> createQueuePolicy(const qpid::framing::FieldTable& settings);
+ static std::auto_ptr<QueuePolicy> createQueuePolicy(uint32_t maxCount, uint64_t maxSize, const std::string& type = REJECT);
+ static void setDefaultMaxSize(uint64_t);
+ friend std::ostream& operator<<(std::ostream&, const QueuePolicy&);
+ protected:
+ QueuePolicy(uint32_t maxCount, uint64_t maxSize, const std::string& type = REJECT);
+
+ virtual void enqueued(const QueuedMessage&);
+ void enqueued(uint64_t size);
+ void dequeued(uint64_t size);
+};
+
+
+class FlowToDiskPolicy : public QueuePolicy
+{
+ public:
+ FlowToDiskPolicy(uint32_t maxCount, uint64_t maxSize);
+ bool checkLimit(const QueuedMessage&);
+};
+
+class RingQueuePolicy : public QueuePolicy
+{
+ public:
+ RingQueuePolicy(uint32_t maxCount, uint64_t maxSize, const std::string& type = RING);
+ void enqueued(const QueuedMessage&);
+ void dequeued(const QueuedMessage&);
+ bool isEnqueued(const QueuedMessage&);
+ bool checkLimit(const QueuedMessage&);
+ private:
+ typedef std::deque<QueuedMessage> Messages;
+ qpid::sys::Mutex lock;
+ Messages queue;
+ const bool strict;
+};
+
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/QueueRegistry.cpp b/RC9/qpid/cpp/src/qpid/broker/QueueRegistry.cpp
new file mode 100644
index 0000000000..2447ce5402
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/QueueRegistry.cpp
@@ -0,0 +1,107 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "QueueRegistry.h"
+#include "qpid/log/Statement.h"
+#include <sstream>
+#include <assert.h>
+
+using namespace qpid::broker;
+using namespace qpid::sys;
+
+QueueRegistry::QueueRegistry() :
+ counter(1), store(0), parent(0), lastNode(false) {}
+
+QueueRegistry::~QueueRegistry(){}
+
+std::pair<Queue::shared_ptr, bool>
+QueueRegistry::declare(const string& declareName, bool durable,
+ bool autoDelete, const OwnershipToken* owner)
+{
+ RWlock::ScopedWlock locker(lock);
+ string name = declareName.empty() ? generateName() : declareName;
+ assert(!name.empty());
+ QueueMap::iterator i = queues.find(name);
+
+ if (i == queues.end()) {
+ Queue::shared_ptr queue(new Queue(name, autoDelete, durable ? store : 0, owner, parent));
+ queues[name] = queue;
+ if (lastNode) queue->setLastNodeFailure();
+
+ return std::pair<Queue::shared_ptr, bool>(queue, true);
+ } else {
+ return std::pair<Queue::shared_ptr, bool>(i->second, false);
+ }
+}
+
+void QueueRegistry::destroyLH (const string& name){
+ queues.erase(name);
+}
+
+void QueueRegistry::destroy (const string& name){
+ RWlock::ScopedWlock locker(lock);
+ destroyLH (name);
+}
+
+Queue::shared_ptr QueueRegistry::find(const string& name){
+ RWlock::ScopedRlock locker(lock);
+ QueueMap::iterator i = queues.find(name);
+
+ if (i == queues.end()) {
+ return Queue::shared_ptr();
+ } else {
+ return i->second;
+ }
+}
+
+string QueueRegistry::generateName(){
+ string name;
+ do {
+ std::stringstream ss;
+ ss << "tmp_" << counter++;
+ name = ss.str();
+ // Thread safety: Private function, only called with lock held
+ // so this is OK.
+ } while(queues.find(name) != queues.end());
+ return name;
+}
+
+void QueueRegistry::setStore (MessageStore* _store)
+{
+ store = _store;
+}
+
+MessageStore* QueueRegistry::getStore() const {
+ return store;
+}
+
+void QueueRegistry::updateQueueClusterState(bool _lastNode)
+{
+ RWlock::ScopedRlock locker(lock);
+ for (QueueMap::iterator i = queues.begin(); i != queues.end(); i++) {
+ if (_lastNode){
+ i->second->setLastNodeFailure();
+ } else {
+ i->second->clearLastNodeFailure();
+ }
+ }
+ lastNode = _lastNode;
+}
+
diff --git a/RC9/qpid/cpp/src/qpid/broker/QueueRegistry.h b/RC9/qpid/cpp/src/qpid/broker/QueueRegistry.h
new file mode 100644
index 0000000000..ca2cd132c4
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/QueueRegistry.h
@@ -0,0 +1,134 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _QueueRegistry_
+#define _QueueRegistry_
+
+#include "Queue.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/management/Manageable.h"
+#include <boost/bind.hpp>
+#include <algorithm>
+#include <map>
+
+namespace qpid {
+namespace broker {
+
+/**
+ * A registry of queues indexed by queue name.
+ *
+ * Queues are reference counted using shared_ptr to ensure that they
+ * are deleted when and only when they are no longer in use.
+ *
+ */
+class QueueRegistry{
+ public:
+ QueueRegistry();
+ ~QueueRegistry();
+
+ /**
+ * Declare a queue.
+ *
+ * @return The queue and a boolean flag which is true if the queue
+ * was created by this declare call false if it already existed.
+ */
+ std::pair<Queue::shared_ptr, bool> declare(const string& name, bool durable = false, bool autodelete = false,
+ const OwnershipToken* owner = 0);
+
+ /**
+ * Destroy the named queue.
+ *
+ * Note: if the queue is in use it is not actually destroyed until
+ * all shared_ptrs to it are destroyed. During that time it is
+ * possible that a new queue with the same name may be
+ * created. This should not create any problems as the new and
+ * old queues exist independently. The registry has
+ * forgotten the old queue so there can be no confusion for
+ * subsequent calls to find or declare with the same name.
+ *
+ */
+ void destroy (const string& name);
+ template <class Test> bool destroyIf(const string& name, Test test)
+ {
+ qpid::sys::RWlock::ScopedWlock locker(lock);
+ if (test()) {
+ destroyLH (name);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Find the named queue. Return 0 if not found.
+ */
+ Queue::shared_ptr find(const string& name);
+
+ /**
+ * Generate unique queue name.
+ */
+ string generateName();
+
+ /**
+ * Set the store to use. May only be called once.
+ */
+ void setStore (MessageStore*);
+
+ /**
+ * Return the message store used.
+ */
+ MessageStore* getStore() const;
+
+ /**
+ * Register the manageable parent for declared queues
+ */
+ void setParent (management::Manageable* _parent) { parent = _parent; }
+
+ /** Call f for each queue in the registry. */
+ template <class F> void eachQueue(F f) const {
+ qpid::sys::RWlock::ScopedWlock l(lock);
+ for (QueueMap::const_iterator i = queues.begin(); i != queues.end(); ++i)
+ f(i->second);
+ }
+
+ /**
+ * Change queue mode when cluster size drops to 1 node, expands again
+ * in practice allows flow queue to disk when last name to be exectuted
+ */
+ void updateQueueClusterState(bool lastNode);
+
+private:
+ typedef std::map<string, Queue::shared_ptr> QueueMap;
+ QueueMap queues;
+ mutable qpid::sys::RWlock lock;
+ int counter;
+ MessageStore* store;
+ management::Manageable* parent;
+ bool lastNode; //used to set mode on queue declare
+
+ //destroy impl that assumes lock is already held:
+ void destroyLH (const string& name);
+};
+
+
+}} // namespace qpid::broker
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/QueuedMessage.h b/RC9/qpid/cpp/src/qpid/broker/QueuedMessage.h
new file mode 100644
index 0000000000..82f5073d87
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/QueuedMessage.h
@@ -0,0 +1,46 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _QueuedMessage_
+#define _QueuedMessage_
+
+#include "Message.h"
+
+namespace qpid {
+namespace broker {
+
+class Queue;
+
+struct QueuedMessage
+{
+ boost::intrusive_ptr<Message> payload;
+ framing::SequenceNumber position;
+ Queue* queue;
+
+ QueuedMessage() : queue(0) {}
+ QueuedMessage(Queue* q, boost::intrusive_ptr<Message> msg, framing::SequenceNumber sn) :
+ payload(msg), position(sn), queue(q) {}
+ QueuedMessage(Queue* q) : queue(q) {}
+};
+
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/RateTracker.cpp b/RC9/qpid/cpp/src/qpid/broker/RateTracker.cpp
new file mode 100644
index 0000000000..fc88d99cfa
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/RateTracker.cpp
@@ -0,0 +1,51 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "RateTracker.h"
+
+using qpid::sys::AbsTime;
+using qpid::sys::Duration;
+using qpid::sys::TIME_SEC;
+
+namespace qpid {
+namespace broker {
+
+RateTracker::RateTracker() : currentCount(0), lastCount(0), lastTime(AbsTime::now()) {}
+
+RateTracker& RateTracker::operator++()
+{
+ ++currentCount;
+ return *this;
+}
+
+double RateTracker::sampleRatePerSecond()
+{
+ int32_t increment = currentCount - lastCount;
+ AbsTime now = AbsTime::now();
+ Duration interval(lastTime, now);
+ lastCount = currentCount;
+ lastTime = now;
+ //if sampling at higher frequency than supported, will just return the number of increments
+ if (interval < TIME_SEC) return increment;
+ else if (increment == 0) return 0;
+ else return increment / (interval / TIME_SEC);
+}
+
+}} // namespace qpid::broker
diff --git a/RC9/qpid/cpp/src/qpid/broker/RateTracker.h b/RC9/qpid/cpp/src/qpid/broker/RateTracker.h
new file mode 100644
index 0000000000..0c20b37312
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/RateTracker.h
@@ -0,0 +1,57 @@
+#ifndef QPID_BROKER_RATETRACKER_H
+#define QPID_BROKER_RATETRACKER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Time.h"
+
+namespace qpid {
+namespace broker {
+
+/**
+ * Simple rate tracker: represents some value that can be incremented,
+ * then can periodcially sample the rate of increments.
+ */
+class RateTracker
+{
+ public:
+ RateTracker();
+ /**
+ * Increments the count being tracked. Can be called concurrently
+ * with other calls to this operator as well as with calls to
+ * sampleRatePerSecond().
+ */
+ RateTracker& operator++();
+ /**
+ * Returns the rate of increments per second since last
+ * called. Calls to this method should be serialised, but can be
+ * called concurrently with the increment operator
+ */
+ double sampleRatePerSecond();
+ private:
+ volatile int32_t currentCount;
+ int32_t lastCount;
+ qpid::sys::AbsTime lastTime;
+};
+}} // namespace qpid::broker
+
+#endif /*!QPID_BROKER_RATETRACKER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/broker/RecoverableConfig.h b/RC9/qpid/cpp/src/qpid/broker/RecoverableConfig.h
new file mode 100644
index 0000000000..838a8582dc
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/RecoverableConfig.h
@@ -0,0 +1,45 @@
+#ifndef _broker_RecoverableConfig_h
+#define _broker_RecoverableConfig_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <boost/shared_ptr.hpp>
+
+namespace qpid {
+namespace broker {
+
+/**
+ * The interface through which configurations are recovered.
+ */
+class RecoverableConfig
+{
+public:
+ typedef boost::shared_ptr<RecoverableConfig> shared_ptr;
+
+ virtual void setPersistenceId(uint64_t id) = 0;
+ virtual ~RecoverableConfig() {};
+};
+
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/RecoverableExchange.h b/RC9/qpid/cpp/src/qpid/broker/RecoverableExchange.h
new file mode 100644
index 0000000000..76d0d2ecdf
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/RecoverableExchange.h
@@ -0,0 +1,50 @@
+#ifndef _broker_RecoverableExchange_h
+#define _broker_RecoverableExchange_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <boost/shared_ptr.hpp>
+#include "qpid/framing/FieldTable.h"
+
+namespace qpid {
+namespace broker {
+
+/**
+ * The interface through which bindings are recovered.
+ */
+class RecoverableExchange
+{
+public:
+ typedef boost::shared_ptr<RecoverableExchange> shared_ptr;
+
+ virtual void setPersistenceId(uint64_t id) = 0;
+ /**
+ * Recover binding. Nb: queue must have been recovered earlier.
+ */
+ virtual void bind(std::string& queue, std::string& routingKey, qpid::framing::FieldTable& args) = 0;
+ virtual ~RecoverableExchange() {};
+};
+
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/RecoverableMessage.h b/RC9/qpid/cpp/src/qpid/broker/RecoverableMessage.h
new file mode 100644
index 0000000000..f755fdf727
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/RecoverableMessage.h
@@ -0,0 +1,58 @@
+#ifndef _broker_RecoverableMessage_h
+#define _broker_RecoverableMessage_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <boost/shared_ptr.hpp>
+#include "qpid/framing/amqp_types.h"
+#include "qpid/framing/Buffer.h"
+
+namespace qpid {
+namespace broker {
+
+/**
+ * The interface through which messages are reloaded on recovery.
+ */
+class RecoverableMessage
+{
+public:
+ typedef boost::shared_ptr<RecoverableMessage> shared_ptr;
+ virtual void setPersistenceId(uint64_t id) = 0;
+ /**
+ * Used by store to determine whether to load content on recovery
+ * or let message load its own content as and when it requires it.
+ *
+ * @returns true if the content of the message should be loaded
+ */
+ virtual bool loadContent(uint64_t available) = 0;
+ /**
+ * Loads the content held in the supplied buffer (may do checking
+ * of length as necessary)
+ */
+ virtual void decodeContent(framing::Buffer& buffer) = 0;
+ virtual ~RecoverableMessage() {};
+};
+
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/RecoverableQueue.h b/RC9/qpid/cpp/src/qpid/broker/RecoverableQueue.h
new file mode 100644
index 0000000000..b32bae7f07
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/RecoverableQueue.h
@@ -0,0 +1,59 @@
+#ifndef _broker_RecoverableQueue_h
+#define _broker_RecoverableQueue_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "RecoverableMessage.h"
+#include <boost/shared_ptr.hpp>
+
+namespace qpid {
+namespace broker {
+
+class ExternalQueueStore;
+
+/**
+ * The interface through which messages are added back to queues on
+ * recovery.
+ */
+class RecoverableQueue
+{
+public:
+ typedef boost::shared_ptr<RecoverableQueue> shared_ptr;
+
+ virtual void setPersistenceId(uint64_t id) = 0;
+ virtual uint64_t getPersistenceId() const = 0;
+ /**
+ * Used during recovery to add stored messages back to the queue
+ */
+ virtual void recover(RecoverableMessage::shared_ptr msg) = 0;
+ virtual ~RecoverableQueue() {};
+
+ virtual const std::string& getName() const = 0;
+ virtual void setExternalQueueStore(ExternalQueueStore* inst) = 0;
+ virtual ExternalQueueStore* getExternalQueueStore() const = 0;
+
+};
+
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/RecoverableTransaction.h b/RC9/qpid/cpp/src/qpid/broker/RecoverableTransaction.h
new file mode 100644
index 0000000000..7fe34b6756
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/RecoverableTransaction.h
@@ -0,0 +1,49 @@
+#ifndef _broker_RecoverableTransaction_h
+#define _broker_RecoverableTransaction_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <boost/shared_ptr.hpp>
+
+#include "RecoverableMessage.h"
+#include "RecoverableQueue.h"
+
+namespace qpid {
+namespace broker {
+
+/**
+ * The interface through which prepared 2pc transactions are
+ * recovered.
+ */
+class RecoverableTransaction
+{
+public:
+ typedef boost::shared_ptr<RecoverableTransaction> shared_ptr;
+ virtual void enqueue(RecoverableQueue::shared_ptr queue, RecoverableMessage::shared_ptr message) = 0;
+ virtual void dequeue(RecoverableQueue::shared_ptr queue, RecoverableMessage::shared_ptr message) = 0;
+ virtual ~RecoverableTransaction() {};
+};
+
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/RecoveredDequeue.cpp b/RC9/qpid/cpp/src/qpid/broker/RecoveredDequeue.cpp
new file mode 100644
index 0000000000..e2d70964fb
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/RecoveredDequeue.cpp
@@ -0,0 +1,40 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "RecoveredDequeue.h"
+
+using boost::intrusive_ptr;
+using namespace qpid::broker;
+
+RecoveredDequeue::RecoveredDequeue(Queue::shared_ptr _queue, intrusive_ptr<Message> _msg) : queue(_queue), msg(_msg) {}
+
+bool RecoveredDequeue::prepare(TransactionContext*) throw(){
+ //should never be called; transaction has already prepared if an enqueue is recovered
+ return false;
+}
+
+void RecoveredDequeue::commit() throw(){
+}
+
+void RecoveredDequeue::rollback() throw(){
+ msg->enqueueComplete();
+ queue->process(msg);
+}
+
diff --git a/RC9/qpid/cpp/src/qpid/broker/RecoveredDequeue.h b/RC9/qpid/cpp/src/qpid/broker/RecoveredDequeue.h
new file mode 100644
index 0000000000..ef6b8f1f74
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/RecoveredDequeue.h
@@ -0,0 +1,57 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _RecoveredDequeue_
+#define _RecoveredDequeue_
+
+#include "Deliverable.h"
+#include "Message.h"
+#include "MessageStore.h"
+#include "Queue.h"
+#include "TxOp.h"
+
+#include <boost/intrusive_ptr.hpp>
+
+#include <algorithm>
+#include <functional>
+#include <list>
+
+namespace qpid {
+ namespace broker {
+ class RecoveredDequeue : public TxOp{
+ Queue::shared_ptr queue;
+ boost::intrusive_ptr<Message> msg;
+
+ public:
+ RecoveredDequeue(Queue::shared_ptr queue, boost::intrusive_ptr<Message> msg);
+ virtual bool prepare(TransactionContext* ctxt) throw();
+ virtual void commit() throw();
+ virtual void rollback() throw();
+ virtual ~RecoveredDequeue(){}
+ virtual void accept(TxOpConstVisitor& visitor) const { visitor(*this); }
+
+ Queue::shared_ptr getQueue() const { return queue; }
+ boost::intrusive_ptr<Message> getMessage() const { return msg; }
+ };
+ }
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/RecoveredEnqueue.cpp b/RC9/qpid/cpp/src/qpid/broker/RecoveredEnqueue.cpp
new file mode 100644
index 0000000000..1984a5d4a8
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/RecoveredEnqueue.cpp
@@ -0,0 +1,40 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "RecoveredEnqueue.h"
+
+using boost::intrusive_ptr;
+using namespace qpid::broker;
+
+RecoveredEnqueue::RecoveredEnqueue(Queue::shared_ptr _queue, intrusive_ptr<Message> _msg) : queue(_queue), msg(_msg) {}
+
+bool RecoveredEnqueue::prepare(TransactionContext*) throw(){
+ //should never be called; transaction has already prepared if an enqueue is recovered
+ return false;
+}
+
+void RecoveredEnqueue::commit() throw(){
+ msg->enqueueComplete();
+ queue->process(msg);
+}
+
+void RecoveredEnqueue::rollback() throw(){
+}
+
diff --git a/RC9/qpid/cpp/src/qpid/broker/RecoveredEnqueue.h b/RC9/qpid/cpp/src/qpid/broker/RecoveredEnqueue.h
new file mode 100644
index 0000000000..2d97768e65
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/RecoveredEnqueue.h
@@ -0,0 +1,58 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _RecoveredEnqueue_
+#define _RecoveredEnqueue_
+
+#include "Deliverable.h"
+#include "Message.h"
+#include "MessageStore.h"
+#include "Queue.h"
+#include "TxOp.h"
+
+#include <boost/intrusive_ptr.hpp>
+
+#include <algorithm>
+#include <functional>
+#include <list>
+
+namespace qpid {
+ namespace broker {
+ class RecoveredEnqueue : public TxOp{
+ Queue::shared_ptr queue;
+ boost::intrusive_ptr<Message> msg;
+
+ public:
+ RecoveredEnqueue(Queue::shared_ptr queue, boost::intrusive_ptr<Message> msg);
+ virtual bool prepare(TransactionContext* ctxt) throw();
+ virtual void commit() throw();
+ virtual void rollback() throw();
+ virtual ~RecoveredEnqueue(){}
+ virtual void accept(TxOpConstVisitor& visitor) const { visitor(*this); }
+
+ Queue::shared_ptr getQueue() const { return queue; }
+ boost::intrusive_ptr<Message> getMessage() const { return msg; }
+
+ };
+ }
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/RecoveryManager.h b/RC9/qpid/cpp/src/qpid/broker/RecoveryManager.h
new file mode 100644
index 0000000000..7dcbe3a2b0
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/RecoveryManager.h
@@ -0,0 +1,61 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _RecoveryManager_
+#define _RecoveryManager_
+
+#include "RecoverableExchange.h"
+#include "RecoverableQueue.h"
+#include "RecoverableMessage.h"
+#include "RecoverableTransaction.h"
+#include "RecoverableConfig.h"
+#include "TransactionalStore.h"
+#include "qpid/framing/Buffer.h"
+
+namespace qpid {
+namespace broker {
+
+class RecoveryManager{
+ public:
+ virtual ~RecoveryManager(){}
+ virtual RecoverableExchange::shared_ptr recoverExchange(framing::Buffer& buffer) = 0;
+ virtual RecoverableQueue::shared_ptr recoverQueue(framing::Buffer& buffer) = 0;
+ virtual RecoverableMessage::shared_ptr recoverMessage(framing::Buffer& buffer) = 0;
+ virtual RecoverableTransaction::shared_ptr recoverTransaction(const std::string& xid,
+ std::auto_ptr<TPCTransactionContext> txn) = 0;
+ virtual RecoverableConfig::shared_ptr recoverConfig(framing::Buffer& buffer) = 0;
+
+ virtual void recoveryComplete() = 0;
+};
+
+class Recoverable {
+ public:
+ virtual ~Recoverable() {}
+
+ /**
+ * Request recovery of queue and message state.
+ */
+ virtual void recover(RecoveryManager& recoverer) = 0;
+};
+
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/RecoveryManagerImpl.cpp b/RC9/qpid/cpp/src/qpid/broker/RecoveryManagerImpl.cpp
new file mode 100644
index 0000000000..d3eacefc3c
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/RecoveryManagerImpl.cpp
@@ -0,0 +1,253 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "RecoveryManagerImpl.h"
+
+#include "Message.h"
+#include "Queue.h"
+#include "Link.h"
+#include "Bridge.h"
+#include "RecoveredEnqueue.h"
+#include "RecoveredDequeue.h"
+#include "qpid/framing/reply_exceptions.h"
+
+using namespace qpid;
+using namespace qpid::broker;
+using boost::dynamic_pointer_cast;
+using boost::intrusive_ptr;
+
+RecoveryManagerImpl::RecoveryManagerImpl(QueueRegistry& _queues, ExchangeRegistry& _exchanges, LinkRegistry& _links,
+ DtxManager& _dtxMgr, uint64_t _stagingThreshold)
+ : queues(_queues), exchanges(_exchanges), links(_links), dtxMgr(_dtxMgr), stagingThreshold(_stagingThreshold) {}
+
+RecoveryManagerImpl::~RecoveryManagerImpl() {}
+
+class RecoverableMessageImpl : public RecoverableMessage
+{
+ intrusive_ptr<Message> msg;
+ const uint64_t stagingThreshold;
+public:
+ RecoverableMessageImpl(const intrusive_ptr<Message>& _msg, uint64_t _stagingThreshold)
+ : msg(_msg), stagingThreshold(_stagingThreshold) {}
+ ~RecoverableMessageImpl() {};
+ void setPersistenceId(uint64_t id);
+ bool loadContent(uint64_t available);
+ void decodeContent(framing::Buffer& buffer);
+ void recover(Queue::shared_ptr queue);
+ void enqueue(DtxBuffer::shared_ptr buffer, Queue::shared_ptr queue);
+ void dequeue(DtxBuffer::shared_ptr buffer, Queue::shared_ptr queue);
+};
+
+class RecoverableQueueImpl : public RecoverableQueue
+{
+ Queue::shared_ptr queue;
+public:
+ RecoverableQueueImpl(const boost::shared_ptr<Queue>& _queue) : queue(_queue) {}
+ ~RecoverableQueueImpl() {};
+ void setPersistenceId(uint64_t id);
+ uint64_t getPersistenceId() const;
+ const std::string& getName() const;
+ void setExternalQueueStore(ExternalQueueStore* inst);
+ ExternalQueueStore* getExternalQueueStore() const;
+ void recover(RecoverableMessage::shared_ptr msg);
+ void enqueue(DtxBuffer::shared_ptr buffer, RecoverableMessage::shared_ptr msg);
+ void dequeue(DtxBuffer::shared_ptr buffer, RecoverableMessage::shared_ptr msg);
+};
+
+class RecoverableExchangeImpl : public RecoverableExchange
+{
+ Exchange::shared_ptr exchange;
+ QueueRegistry& queues;
+public:
+ RecoverableExchangeImpl(Exchange::shared_ptr _exchange, QueueRegistry& _queues) : exchange(_exchange), queues(_queues) {}
+ void setPersistenceId(uint64_t id);
+ void bind(std::string& queue, std::string& routingKey, qpid::framing::FieldTable& args);
+};
+
+class RecoverableConfigImpl : public RecoverableConfig
+{
+ Link::shared_ptr link;
+ Bridge::shared_ptr bridge;
+public:
+ RecoverableConfigImpl(Link::shared_ptr _link) : link(_link) {}
+ RecoverableConfigImpl(Bridge::shared_ptr _bridge) : bridge(_bridge) {}
+ void setPersistenceId(uint64_t id);
+};
+
+class RecoverableTransactionImpl : public RecoverableTransaction
+{
+ DtxBuffer::shared_ptr buffer;
+public:
+ RecoverableTransactionImpl(DtxBuffer::shared_ptr _buffer) : buffer(_buffer) {}
+ void enqueue(RecoverableQueue::shared_ptr queue, RecoverableMessage::shared_ptr message);
+ void dequeue(RecoverableQueue::shared_ptr queue, RecoverableMessage::shared_ptr message);
+};
+
+RecoverableExchange::shared_ptr RecoveryManagerImpl::recoverExchange(framing::Buffer& buffer)
+{
+ return RecoverableExchange::shared_ptr(new RecoverableExchangeImpl(Exchange::decode(exchanges, buffer), queues));
+}
+
+RecoverableQueue::shared_ptr RecoveryManagerImpl::recoverQueue(framing::Buffer& buffer)
+{
+ Queue::shared_ptr queue = Queue::decode(queues, buffer);
+ try {
+ Exchange::shared_ptr exchange = exchanges.getDefault();
+ if (exchange) {
+ exchange->bind(queue, queue->getName(), 0);
+ }
+ } catch (const framing::NotFoundException& /*e*/) {
+ //assume no default exchange has been declared
+ }
+ return RecoverableQueue::shared_ptr(new RecoverableQueueImpl(queue));
+}
+
+RecoverableMessage::shared_ptr RecoveryManagerImpl::recoverMessage(framing::Buffer& buffer)
+{
+ boost::intrusive_ptr<Message> message(new Message());
+ message->decodeHeader(buffer);
+ return RecoverableMessage::shared_ptr(new RecoverableMessageImpl(message, stagingThreshold));
+}
+
+RecoverableTransaction::shared_ptr RecoveryManagerImpl::recoverTransaction(const std::string& xid,
+ std::auto_ptr<TPCTransactionContext> txn)
+{
+ DtxBuffer::shared_ptr buffer(new DtxBuffer());
+ dtxMgr.recover(xid, txn, buffer);
+ return RecoverableTransaction::shared_ptr(new RecoverableTransactionImpl(buffer));
+}
+
+RecoverableConfig::shared_ptr RecoveryManagerImpl::recoverConfig(framing::Buffer& buffer)
+{
+ string kind;
+
+ buffer.getShortString (kind);
+ if (kind == "link")
+ return RecoverableConfig::shared_ptr(new RecoverableConfigImpl(Link::decode (links, buffer)));
+ else if (kind == "bridge")
+ return RecoverableConfig::shared_ptr(new RecoverableConfigImpl(Bridge::decode (links, buffer)));
+
+ return RecoverableConfig::shared_ptr(); // TODO: raise an exception instead
+}
+
+void RecoveryManagerImpl::recoveryComplete()
+{
+ //TODO (finalise binding setup etc)
+}
+
+bool RecoverableMessageImpl::loadContent(uint64_t available)
+{
+ return !stagingThreshold || available < stagingThreshold;
+}
+
+void RecoverableMessageImpl::decodeContent(framing::Buffer& buffer)
+{
+ msg->decodeContent(buffer);
+}
+
+void RecoverableMessageImpl::recover(Queue::shared_ptr queue)
+{
+ queue->recover(msg);
+}
+
+void RecoverableMessageImpl::setPersistenceId(uint64_t id)
+{
+ msg->setPersistenceId(id);
+}
+
+void RecoverableQueueImpl::recover(RecoverableMessage::shared_ptr msg)
+{
+ dynamic_pointer_cast<RecoverableMessageImpl>(msg)->recover(queue);
+}
+
+void RecoverableQueueImpl::setPersistenceId(uint64_t id)
+{
+ queue->setPersistenceId(id);
+}
+
+uint64_t RecoverableQueueImpl::getPersistenceId() const
+{
+ return queue->getPersistenceId();
+}
+
+const std::string& RecoverableQueueImpl::getName() const
+{
+ return queue->getName();
+}
+
+void RecoverableQueueImpl::setExternalQueueStore(ExternalQueueStore* inst)
+{
+ queue->setExternalQueueStore(inst);
+}
+
+ExternalQueueStore* RecoverableQueueImpl::getExternalQueueStore() const
+{
+ return queue->getExternalQueueStore();
+}
+
+void RecoverableExchangeImpl::setPersistenceId(uint64_t id)
+{
+ exchange->setPersistenceId(id);
+}
+
+void RecoverableConfigImpl::setPersistenceId(uint64_t id)
+{
+ if (link.get())
+ link->setPersistenceId(id);
+ else if (bridge.get())
+ bridge->setPersistenceId(id);
+}
+
+void RecoverableExchangeImpl::bind(string& queueName, string& key, framing::FieldTable& args)
+{
+ Queue::shared_ptr queue = queues.find(queueName);
+ exchange->bind(queue, key, &args);
+}
+
+void RecoverableMessageImpl::dequeue(DtxBuffer::shared_ptr buffer, Queue::shared_ptr queue)
+{
+ buffer->enlist(TxOp::shared_ptr(new RecoveredDequeue(queue, msg)));
+}
+
+void RecoverableMessageImpl::enqueue(DtxBuffer::shared_ptr buffer, Queue::shared_ptr queue)
+{
+ msg->enqueueComplete(); // recoved nmessage to enqueued in store already
+ buffer->enlist(TxOp::shared_ptr(new RecoveredEnqueue(queue, msg)));
+}
+
+void RecoverableQueueImpl::dequeue(DtxBuffer::shared_ptr buffer, RecoverableMessage::shared_ptr message)
+{
+ dynamic_pointer_cast<RecoverableMessageImpl>(message)->dequeue(buffer, queue);
+}
+
+void RecoverableQueueImpl::enqueue(DtxBuffer::shared_ptr buffer, RecoverableMessage::shared_ptr message)
+{
+ dynamic_pointer_cast<RecoverableMessageImpl>(message)->enqueue(buffer, queue);
+}
+
+void RecoverableTransactionImpl::dequeue(RecoverableQueue::shared_ptr queue, RecoverableMessage::shared_ptr message)
+{
+ dynamic_pointer_cast<RecoverableQueueImpl>(queue)->dequeue(buffer, message);
+}
+
+void RecoverableTransactionImpl::enqueue(RecoverableQueue::shared_ptr queue, RecoverableMessage::shared_ptr message)
+{
+ dynamic_pointer_cast<RecoverableQueueImpl>(queue)->enqueue(buffer, message);
+}
diff --git a/RC9/qpid/cpp/src/qpid/broker/RecoveryManagerImpl.h b/RC9/qpid/cpp/src/qpid/broker/RecoveryManagerImpl.h
new file mode 100644
index 0000000000..cd34d464f5
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/RecoveryManagerImpl.h
@@ -0,0 +1,59 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _RecoveryManagerImpl_
+#define _RecoveryManagerImpl_
+
+#include <list>
+#include "DtxManager.h"
+#include "ExchangeRegistry.h"
+#include "QueueRegistry.h"
+#include "LinkRegistry.h"
+#include "RecoveryManager.h"
+
+namespace qpid {
+namespace broker {
+
+ class RecoveryManagerImpl : public RecoveryManager{
+ QueueRegistry& queues;
+ ExchangeRegistry& exchanges;
+ LinkRegistry& links;
+ DtxManager& dtxMgr;
+ const uint64_t stagingThreshold;
+ public:
+ RecoveryManagerImpl(QueueRegistry& queues, ExchangeRegistry& exchanges, LinkRegistry& links,
+ DtxManager& dtxMgr, uint64_t stagingThreshold);
+ ~RecoveryManagerImpl();
+
+ RecoverableExchange::shared_ptr recoverExchange(framing::Buffer& buffer);
+ RecoverableQueue::shared_ptr recoverQueue(framing::Buffer& buffer);
+ RecoverableMessage::shared_ptr recoverMessage(framing::Buffer& buffer);
+ RecoverableTransaction::shared_ptr recoverTransaction(const std::string& xid,
+ std::auto_ptr<TPCTransactionContext> txn);
+ RecoverableConfig::shared_ptr recoverConfig(framing::Buffer& buffer);
+ void recoveryComplete();
+ };
+
+
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/SaslAuthenticator.cpp b/RC9/qpid/cpp/src/qpid/broker/SaslAuthenticator.cpp
new file mode 100644
index 0000000000..370de8a1d1
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/SaslAuthenticator.cpp
@@ -0,0 +1,337 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "Connection.h"
+#include "qpid/log/Statement.h"
+#include "qpid/framing/reply_exceptions.h"
+#include <boost/format.hpp>
+
+#if HAVE_SASL
+#include <sasl/sasl.h>
+#endif
+
+using namespace qpid::framing;
+using boost::format;
+using boost::str;
+
+namespace qpid {
+namespace broker {
+
+
+class NullAuthenticator : public SaslAuthenticator
+{
+ Connection& connection;
+ framing::AMQP_ClientProxy::Connection client;
+ std::string realm;
+public:
+ NullAuthenticator(Connection& connection);
+ ~NullAuthenticator();
+ void getMechanisms(framing::Array& mechanisms);
+ void start(const std::string& mechanism, const std::string& response);
+ void step(const std::string&) {}
+};
+
+#if HAVE_SASL
+
+class CyrusAuthenticator : public SaslAuthenticator
+{
+ sasl_conn_t *sasl_conn;
+ Connection& connection;
+ framing::AMQP_ClientProxy::Connection client;
+
+ void processAuthenticationStep(int code, const char *challenge, unsigned int challenge_len);
+
+public:
+ CyrusAuthenticator(Connection& connection);
+ ~CyrusAuthenticator();
+ void init();
+ void getMechanisms(framing::Array& mechanisms);
+ void start(const std::string& mechanism, const std::string& response);
+ void step(const std::string& response);
+ void getUid(std::string& uid);
+ void getError(std::string& error);
+};
+
+bool SaslAuthenticator::available(void)
+{
+ return true;
+}
+
+// Initialize the SASL mechanism; throw if it fails.
+void SaslAuthenticator::init(const std::string& saslName)
+{
+ int code = sasl_server_init(NULL, saslName.c_str());
+ if (code != SASL_OK) {
+ // TODO: Figure out who owns the char* returned by
+ // sasl_errstring, though it probably does not matter much
+ throw Exception(sasl_errstring(code, NULL, NULL));
+ }
+}
+
+void SaslAuthenticator::fini(void)
+{
+ sasl_done();
+}
+
+#else
+
+typedef NullAuthenticator CyrusAuthenticator;
+
+bool SaslAuthenticator::available(void)
+{
+ return false;
+}
+
+void SaslAuthenticator::init(const std::string& /*saslName*/)
+{
+ throw Exception("Requested authentication but SASL unavailable");
+}
+
+void SaslAuthenticator::fini(void)
+{
+ return;
+}
+
+#endif
+
+std::auto_ptr<SaslAuthenticator> SaslAuthenticator::createAuthenticator(Connection& c)
+{
+ static bool needWarning = true;
+ if (c.getBroker().getOptions().auth) {
+ return std::auto_ptr<SaslAuthenticator>(new CyrusAuthenticator(c));
+ } else {
+ QPID_LOG(warning, "SASL: No Authentication Performed");
+ needWarning = false;
+ return std::auto_ptr<SaslAuthenticator>(new NullAuthenticator(c));
+ }
+}
+
+NullAuthenticator::NullAuthenticator(Connection& c) : connection(c), client(c.getOutput()),
+ realm(c.getBroker().getOptions().realm) {}
+NullAuthenticator::~NullAuthenticator() {}
+
+void NullAuthenticator::getMechanisms(Array& mechanisms)
+{
+ mechanisms.add(boost::shared_ptr<FieldValue>(new Str16Value("ANONYMOUS")));
+}
+
+void NullAuthenticator::start(const string& mechanism, const string& response)
+{
+ if (mechanism == "PLAIN") { // Old behavior
+ if (response.size() > 0 && response[0] == (char) 0) {
+ string temp = response.substr(1);
+ string::size_type i = temp.find((char)0);
+ string uid = temp.substr(0, i);
+ string pwd = temp.substr(i + 1);
+ i = uid.find_last_of(realm);
+ if (i == string::npos || i != (uid.size() - 1)) {
+ uid = str(format("%1%@%2%") % uid % realm);
+ }
+ connection.setUserId(uid);
+ }
+ } else {
+ connection.setUserId("anonymous");
+ }
+ client.tune(framing::CHANNEL_MAX, connection.getFrameMax(), 0, 0);
+}
+
+
+#if HAVE_SASL
+
+CyrusAuthenticator::CyrusAuthenticator(Connection& c) : sasl_conn(0), connection(c), client(c.getOutput())
+{
+ init();
+}
+
+void CyrusAuthenticator::init()
+{
+ /* Next to the service name, which specifies the
+ * /etc/sasl2/<service name>.conf file to read, the realm is
+ * currently the most important argument below. When
+ * performing authentication the user that is authenticating
+ * will be looked up in a specific realm. If none is given
+ * then the realm defaults to the hostname, which can cause
+ * confusion when the daemon is run on different hosts that
+ * may be logically sharing a realm (aka a user domain). This
+ * is especially important for SASL PLAIN authentication,
+ * which cannot specify a realm for the user that is
+ * authenticating.
+ */
+ const char *realm = connection.getBroker().getOptions().realm.c_str();
+ int code = sasl_server_new(BROKER_SASL_NAME, /* Service name */
+ NULL, /* Server FQDN, gethostname() */
+ realm, /* Authentication realm */
+ NULL, /* Local IP, needed for some mechanism */
+ NULL, /* Remote IP, needed for some mechanism */
+ NULL, /* Callbacks */
+ 0, /* Connection flags */
+ &sasl_conn);
+
+ if (SASL_OK != code) {
+ QPID_LOG(info, "SASL: Connection creation failed: [" << code << "] " << sasl_errdetail(sasl_conn));
+
+ // TODO: Change this to an exception signaling
+ // server error, when one is available
+ throw ConnectionForcedException("Unable to perform authentication");
+ }
+}
+
+CyrusAuthenticator::~CyrusAuthenticator()
+{
+ if (sasl_conn) {
+ sasl_dispose(&sasl_conn);
+ sasl_conn = 0;
+ }
+}
+
+void CyrusAuthenticator::getError(string& error)
+{
+ error = string(sasl_errdetail(sasl_conn));
+}
+
+void CyrusAuthenticator::getUid(string& uid)
+{
+ int code;
+ const void* ptr;
+
+ code = sasl_getprop(sasl_conn, SASL_USERNAME, &ptr);
+ if (SASL_OK != code)
+ return;
+
+ uid = string(const_cast<char*>(static_cast<const char*>(ptr)));
+}
+
+void CyrusAuthenticator::getMechanisms(Array& mechanisms)
+{
+ const char *separator = " ";
+ const char *list;
+ unsigned int list_len;
+ int count;
+
+ int code = sasl_listmech(sasl_conn, NULL,
+ "", separator, "",
+ &list, &list_len,
+ &count);
+
+ if (SASL_OK != code) {
+ QPID_LOG(info, "SASL: Mechanism listing failed: " << sasl_errdetail(sasl_conn));
+
+ // TODO: Change this to an exception signaling
+ // server error, when one is available
+ throw ConnectionForcedException("Mechanism listing failed");
+ } else {
+ string mechanism;
+ unsigned int start;
+ unsigned int end;
+
+ QPID_LOG(info, "SASL: Mechanism list: " << list);
+
+ end = 0;
+ do {
+ start = end;
+
+ // Seek to end of next mechanism
+ while (end < list_len && separator[0] != list[end])
+ end++;
+
+ // Record the mechanism
+ mechanisms.add(boost::shared_ptr<FieldValue>(new Str16Value(string(list, start, end - start))));
+ end++;
+ } while (end < list_len);
+ }
+}
+
+void CyrusAuthenticator::start(const string& mechanism, const string& response)
+{
+ const char *challenge;
+ unsigned int challenge_len;
+
+ QPID_LOG(info, "SASL: Starting authentication with mechanism: " << mechanism);
+ int code = sasl_server_start(sasl_conn,
+ mechanism.c_str(),
+ response.c_str(), response.length(),
+ &challenge, &challenge_len);
+
+ processAuthenticationStep(code, challenge, challenge_len);
+}
+
+void CyrusAuthenticator::step(const string& response)
+{
+ const char *challenge;
+ unsigned int challenge_len;
+
+ int code = sasl_server_step(sasl_conn,
+ response.c_str(), response.length(),
+ &challenge, &challenge_len);
+
+ processAuthenticationStep(code, challenge, challenge_len);
+}
+
+void CyrusAuthenticator::processAuthenticationStep(int code, const char *challenge, unsigned int challenge_len)
+{
+ if (SASL_OK == code) {
+ const void *uid;
+
+ code = sasl_getprop(sasl_conn, SASL_USERNAME, &uid);
+ if (SASL_OK != code) {
+ QPID_LOG(info, "SASL: Authentication succeeded, username unavailable");
+ // TODO: Change this to an exception signaling
+ // authentication failure, when one is available
+ throw ConnectionForcedException("Authenticated username unavailable");
+ }
+
+ QPID_LOG(info, "SASL: Authentication succeeded for: "
+ << const_cast<char*>(static_cast<const char*>(uid)));
+
+ connection.setUserId(const_cast<char*>(static_cast<const char*>(uid)));
+
+ client.tune(framing::CHANNEL_MAX, connection.getFrameMax(), 0, 0);
+ } else if (SASL_CONTINUE == code) {
+ string challenge_str(challenge, challenge_len);
+
+ QPID_LOG(debug, "SASL: sending challenge to client");
+
+ client.secure(challenge_str);
+ } else {
+ QPID_LOG(info, "SASL: Authentication failed: " << sasl_errdetail(sasl_conn));
+
+ // TODO: Change to more specific exceptions, when they are
+ // available
+ switch (code) {
+ case SASL_NOMECH:
+ throw ConnectionForcedException("Unsupported mechanism");
+ break;
+ case SASL_TRYAGAIN:
+ throw ConnectionForcedException("Transient failure, try again");
+ break;
+ default:
+ throw ConnectionForcedException("Authentication failed");
+ break;
+ }
+ }
+}
+#endif
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/broker/SaslAuthenticator.h b/RC9/qpid/cpp/src/qpid/broker/SaslAuthenticator.h
new file mode 100644
index 0000000000..2598b6d177
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/SaslAuthenticator.h
@@ -0,0 +1,55 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _SaslAuthenticator_
+#define _SaslAuthenticator_
+
+#include "qpid/framing/amqp_types.h"
+#include "qpid/framing/AMQP_ClientProxy.h"
+#include "qpid/Exception.h"
+#include <memory>
+
+namespace qpid {
+namespace broker {
+
+class Connection;
+
+class SaslAuthenticator
+{
+public:
+ virtual ~SaslAuthenticator() {}
+ virtual void getMechanisms(framing::Array& mechanisms) = 0;
+ virtual void start(const std::string& mechanism, const std::string& response) = 0;
+ virtual void step(const std::string& response) = 0;
+ virtual void getUid(std::string&) {}
+ virtual void getError(std::string&) {}
+
+ static bool available(void);
+
+ // Initialize the SASL mechanism; throw if it fails.
+ static void init(const std::string& saslName);
+ static void fini(void);
+
+ static std::auto_ptr<SaslAuthenticator> createAuthenticator(Connection& connection);
+};
+
+}}
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/SemanticState.cpp b/RC9/qpid/cpp/src/qpid/broker/SemanticState.cpp
new file mode 100644
index 0000000000..d9896b388b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/SemanticState.cpp
@@ -0,0 +1,669 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "SessionState.h"
+#include "Connection.h"
+#include "DeliverableMessage.h"
+#include "DtxAck.h"
+#include "DtxTimeout.h"
+#include "Message.h"
+#include "Queue.h"
+#include "SessionContext.h"
+#include "TxAccept.h"
+#include "TxPublish.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/log/Statement.h"
+#include "qpid/ptr_map.h"
+#include "AclModule.h"
+
+#include <boost/bind.hpp>
+#include <boost/format.hpp>
+
+#include <iostream>
+#include <sstream>
+#include <algorithm>
+#include <functional>
+
+#include <assert.h>
+
+
+namespace qpid {
+namespace broker {
+
+using std::mem_fun_ref;
+using boost::intrusive_ptr;
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::sys;
+using qpid::ptr_map_ptr;
+
+SemanticState::SemanticState(DeliveryAdapter& da, SessionContext& ss)
+ : session(ss),
+ deliveryAdapter(da),
+ tagGenerator("sgen"),
+ dtxSelected(false),
+ outputTasks(ss),
+ authMsg(getSession().getBroker().getOptions().auth && !getSession().getConnection().isFederationLink()),
+ userID(getSession().getConnection().getUserId().substr(0,getSession().getConnection().getUserId().find('@')))
+{
+ acl = getSession().getBroker().getAcl();
+}
+
+SemanticState::~SemanticState() {
+ //cancel all consumers
+ for (ConsumerImplMap::iterator i = consumers.begin(); i != consumers.end(); i++) {
+ cancel(i->second);
+ }
+
+ if (dtxBuffer.get()) {
+ dtxBuffer->fail();
+ }
+ recover(true);
+}
+
+bool SemanticState::exists(const string& consumerTag){
+ return consumers.find(consumerTag) != consumers.end();
+}
+
+void SemanticState::consume(const string& tag,
+ Queue::shared_ptr queue, bool ackRequired, bool acquire,
+ bool exclusive, const string& resumeId, uint64_t resumeTtl, const FieldTable& arguments)
+{
+ ConsumerImpl::shared_ptr c(new ConsumerImpl(this, tag, queue, ackRequired, acquire, exclusive, resumeId, resumeTtl, arguments));
+ queue->consume(c, exclusive);//may throw exception
+ outputTasks.addOutputTask(c.get());
+ consumers[tag] = c;
+}
+
+void SemanticState::cancel(const string& tag){
+ ConsumerImplMap::iterator i = consumers.find(tag);
+ if (i != consumers.end()) {
+ cancel(i->second);
+ consumers.erase(i);
+ //should cancel all unacked messages for this consumer so that
+ //they are not redelivered on recovery
+ for_each(unacked.begin(), unacked.end(), boost::bind(&DeliveryRecord::cancel, _1, tag));
+
+ }
+}
+
+
+void SemanticState::startTx()
+{
+ txBuffer = TxBuffer::shared_ptr(new TxBuffer());
+}
+
+void SemanticState::commit(MessageStore* const store)
+{
+ if (!txBuffer) throw
+ CommandInvalidException(QPID_MSG("Session has not been selected for use with transactions"));
+
+ TxOp::shared_ptr txAck(static_cast<TxOp*>(new TxAccept(accumulatedAck, unacked)));
+ txBuffer->enlist(txAck);
+ if (txBuffer->commitLocal(store)) {
+ accumulatedAck.clear();
+ } else {
+ throw InternalErrorException(QPID_MSG("Commit failed"));
+ }
+}
+
+void SemanticState::rollback()
+{
+ if (!txBuffer)
+ throw CommandInvalidException(QPID_MSG("Session has not been selected for use with transactions"));
+
+ txBuffer->rollback();
+ accumulatedAck.clear();
+}
+
+void SemanticState::selectDtx()
+{
+ dtxSelected = true;
+}
+
+void SemanticState::startDtx(const std::string& xid, DtxManager& mgr, bool join)
+{
+ if (!dtxSelected) {
+ throw CommandInvalidException(QPID_MSG("Session has not been selected for use with dtx"));
+ }
+ dtxBuffer = DtxBuffer::shared_ptr(new DtxBuffer(xid));
+ txBuffer = static_pointer_cast<TxBuffer>(dtxBuffer);
+ if (join) {
+ mgr.join(xid, dtxBuffer);
+ } else {
+ mgr.start(xid, dtxBuffer);
+ }
+}
+
+void SemanticState::endDtx(const std::string& xid, bool fail)
+{
+ if (!dtxBuffer) {
+ throw IllegalStateException(QPID_MSG("xid " << xid << " not associated with this session"));
+ }
+ if (dtxBuffer->getXid() != xid) {
+ throw CommandInvalidException(
+ QPID_MSG("xid specified on start was " << dtxBuffer->getXid() << ", but " << xid << " specified on end"));
+
+ }
+
+ txBuffer.reset();//ops on this session no longer transactional
+
+ checkDtxTimeout();
+ if (fail) {
+ dtxBuffer->fail();
+ } else {
+ dtxBuffer->markEnded();
+ }
+ dtxBuffer.reset();
+}
+
+void SemanticState::suspendDtx(const std::string& xid)
+{
+ if (dtxBuffer->getXid() != xid) {
+ throw CommandInvalidException(
+ QPID_MSG("xid specified on start was " << dtxBuffer->getXid() << ", but " << xid << " specified on suspend"));
+ }
+ txBuffer.reset();//ops on this session no longer transactional
+
+ checkDtxTimeout();
+ dtxBuffer->setSuspended(true);
+ suspendedXids[xid] = dtxBuffer;
+ dtxBuffer.reset();
+}
+
+void SemanticState::resumeDtx(const std::string& xid)
+{
+ if (!dtxSelected) {
+ throw CommandInvalidException(QPID_MSG("Session has not been selected for use with dtx"));
+ }
+
+ dtxBuffer = suspendedXids[xid];
+ if (!dtxBuffer) {
+ throw CommandInvalidException(QPID_MSG("xid " << xid << " not attached"));
+ } else {
+ suspendedXids.erase(xid);
+ }
+
+ if (dtxBuffer->getXid() != xid) {
+ throw CommandInvalidException(
+ QPID_MSG("xid specified on start was " << dtxBuffer->getXid() << ", but " << xid << " specified on resume"));
+
+ }
+ if (!dtxBuffer->isSuspended()) {
+ throw CommandInvalidException(QPID_MSG("xid " << xid << " not suspended"));
+ }
+
+ checkDtxTimeout();
+ dtxBuffer->setSuspended(false);
+ txBuffer = static_pointer_cast<TxBuffer>(dtxBuffer);
+}
+
+void SemanticState::checkDtxTimeout()
+{
+ if (dtxBuffer->isExpired()) {
+ dtxBuffer.reset();
+ throw DtxTimeoutException();
+ }
+}
+
+void SemanticState::record(const DeliveryRecord& delivery)
+{
+ unacked.push_back(delivery);
+}
+
+SemanticState::ConsumerImpl::ConsumerImpl(SemanticState* _parent,
+ const string& _name,
+ Queue::shared_ptr _queue,
+ bool ack,
+ bool _acquire,
+ bool _exclusive,
+ const string& _resumeId,
+ uint64_t _resumeTtl,
+ const framing::FieldTable& _arguments
+
+
+) :
+ Consumer(_acquire),
+ parent(_parent),
+ name(_name),
+ queue(_queue),
+ ackExpected(ack),
+ acquire(_acquire),
+ blocked(true),
+ windowing(true),
+ exclusive(_exclusive),
+ resumeId(_resumeId),
+ resumeTtl(_resumeTtl),
+ arguments(_arguments),
+ msgCredit(0),
+ byteCredit(0),
+ notifyEnabled(true) {}
+
+OwnershipToken* SemanticState::ConsumerImpl::getSession()
+{
+ return &(parent->session);
+}
+
+bool SemanticState::ConsumerImpl::deliver(QueuedMessage& msg)
+{
+ allocateCredit(msg.payload);
+ DeliveryRecord record(msg, queue, name, acquire, !ackExpected, windowing);
+ parent->deliver(record);
+ if (!ackExpected) record.setEnded();//allows message to be released now its been delivered
+ if (windowing || ackExpected || !acquire) {
+ parent->record(record);
+ }
+ if (acquire && !ackExpected) {
+ queue->dequeue(0, msg);
+ }
+ return true;
+}
+
+bool SemanticState::ConsumerImpl::filter(intrusive_ptr<Message>)
+{
+ return true;
+}
+
+bool SemanticState::ConsumerImpl::accept(intrusive_ptr<Message> msg)
+{
+ blocked = !(filter(msg) && checkCredit(msg));
+ return !blocked;
+}
+
+void SemanticState::ConsumerImpl::allocateCredit(intrusive_ptr<Message>& msg)
+{
+ uint32_t originalMsgCredit = msgCredit;
+ uint32_t originalByteCredit = byteCredit;
+ if (msgCredit != 0xFFFFFFFF) {
+ msgCredit--;
+ }
+ if (byteCredit != 0xFFFFFFFF) {
+ byteCredit -= msg->getRequiredCredit();
+ }
+ QPID_LOG(debug, "Credit allocated for '" << name << "' on " << parent
+ << ", was " << " bytes: " << originalByteCredit << " msgs: " << originalMsgCredit
+ << " now bytes: " << byteCredit << " msgs: " << msgCredit);
+
+}
+
+bool SemanticState::ConsumerImpl::checkCredit(intrusive_ptr<Message>& msg)
+{
+ if (msgCredit == 0 || (byteCredit != 0xFFFFFFFF && byteCredit < msg->getRequiredCredit())) {
+ QPID_LOG(debug, "Not enough credit for '" << name << "' on " << parent
+ << ", bytes: " << byteCredit << " msgs: " << msgCredit);
+ return false;
+ } else {
+ QPID_LOG(debug, "Credit available for '" << name << "' on " << parent
+ << " bytes: " << byteCredit << " msgs: " << msgCredit);
+ return true;
+ }
+}
+
+SemanticState::ConsumerImpl::~ConsumerImpl() {}
+
+void SemanticState::cancel(ConsumerImpl::shared_ptr c)
+{
+ c->disableNotify();
+ outputTasks.removeOutputTask(c.get());
+ Queue::shared_ptr queue = c->getQueue();
+ if(queue) {
+ queue->cancel(c);
+ if (queue->canAutoDelete() && !queue->hasExclusiveOwner()) {
+ Queue::tryAutoDelete(session.getBroker(), queue);
+ }
+ }
+}
+
+void SemanticState::handle(intrusive_ptr<Message> msg) {
+ if (txBuffer.get()) {
+ TxPublish* deliverable(new TxPublish(msg));
+ TxOp::shared_ptr op(deliverable);
+ route(msg, *deliverable);
+ txBuffer->enlist(op);
+ } else {
+ DeliverableMessage deliverable(msg);
+ route(msg, deliverable);
+ }
+}
+
+namespace
+{
+const std::string nullstring;
+}
+
+void SemanticState::route(intrusive_ptr<Message> msg, Deliverable& strategy) {
+ std::string exchangeName = msg->getExchangeName();
+ //TODO: the following should be hidden behind message (using MessageAdapter or similar)
+
+ // Do not replace the delivery-properties.exchange if it is is already set.
+ // This is used internally (by the cluster) to force the exchange name on a message.
+ // The client library ensures this is always empty for messages from normal clients.
+ if (msg->isA<MessageTransferBody>()) {
+ if (!msg->hasProperties<DeliveryProperties>() ||
+ msg->getProperties<DeliveryProperties>()->getExchange().empty())
+ msg->getProperties<DeliveryProperties>()->setExchange(exchangeName);
+ msg->setTimestamp();
+ }
+ if (!cacheExchange || cacheExchange->getName() != exchangeName){
+ cacheExchange = session.getBroker().getExchanges().get(exchangeName);
+ }
+
+ /* verify the userid if specified: */
+ std::string id =
+ msg->hasProperties<MessageProperties>() ? msg->getProperties<MessageProperties>()->getUserId() : nullstring;
+
+ if (authMsg && !id.empty() && id != userID )
+ {
+ QPID_LOG(debug, "authorised user id : " << userID << " but user id in message declared as " << id);
+ throw UnauthorizedAccessException(QPID_MSG("authorised user id : " << userID << " but user id in message declared as " << id));
+ }
+
+ if (acl && acl->doTransferAcl())
+ {
+ if (!acl->authorise(getSession().getConnection().getUserId(),acl::ACT_PUBLISH,acl::OBJ_EXCHANGE,exchangeName, msg->getRoutingKey() ))
+ throw NotAllowedException(QPID_MSG(getSession().getConnection().getUserId() << " cannot publish to " <<
+ exchangeName << " with routing-key " << msg->getRoutingKey()));
+ }
+
+ cacheExchange->route(strategy, msg->getRoutingKey(), msg->getApplicationHeaders());
+
+ if (!strategy.delivered) {
+ //TODO:if discard-unroutable, just drop it
+ //TODO:else if accept-mode is explicit, reject it
+ //else route it to alternate exchange
+ if (cacheExchange->getAlternate()) {
+ cacheExchange->getAlternate()->route(strategy, msg->getRoutingKey(), msg->getApplicationHeaders());
+ }
+ if (!strategy.delivered) {
+ msg->destroy();
+ }
+ }
+
+}
+
+void SemanticState::requestDispatch()
+{
+ for (ConsumerImplMap::iterator i = consumers.begin(); i != consumers.end(); i++) {
+ requestDispatch(*(i->second));
+ }
+}
+
+void SemanticState::requestDispatch(ConsumerImpl& c)
+{
+ if(c.isBlocked())
+ outputTasks.activateOutput();
+}
+
+void SemanticState::complete(DeliveryRecord& delivery)
+{
+ ConsumerImplMap::iterator i = consumers.find(delivery.getTag());
+ if (i != consumers.end()) {
+ i->second->complete(delivery);
+ }
+}
+
+void SemanticState::ConsumerImpl::complete(DeliveryRecord& delivery)
+{
+ if (!delivery.isComplete()) {
+ delivery.complete();
+ if (windowing) {
+ if (msgCredit != 0xFFFFFFFF) msgCredit++;
+ if (byteCredit != 0xFFFFFFFF) byteCredit += delivery.getCredit();
+ }
+ }
+}
+
+void SemanticState::recover(bool requeue)
+{
+ if(requeue){
+ //take copy and clear unacked as requeue may result in redelivery to this session
+ //which will in turn result in additions to unacked
+ DeliveryRecords copy = unacked;
+ unacked.clear();
+ for_each(copy.rbegin(), copy.rend(), mem_fun_ref(&DeliveryRecord::requeue));
+ }else{
+ for_each(unacked.begin(), unacked.end(), boost::bind(&DeliveryRecord::redeliver, _1, this));
+ //unconfirmed messages re redelivered and therefore have their
+ //id adjusted, confirmed messages are not and so the ordering
+ //w.r.t id is lost
+ unacked.sort();
+ }
+}
+
+void SemanticState::deliver(DeliveryRecord& msg)
+{
+ return deliveryAdapter.deliver(msg);
+}
+
+SemanticState::ConsumerImpl& SemanticState::find(const std::string& destination)
+{
+ ConsumerImplMap::iterator i = consumers.find(destination);
+ if (i == consumers.end()) {
+ throw NotFoundException(QPID_MSG("Unknown destination " << destination));
+ } else {
+ return *(i->second);
+ }
+}
+
+void SemanticState::setWindowMode(const std::string& destination)
+{
+ find(destination).setWindowMode();
+}
+
+void SemanticState::setCreditMode(const std::string& destination)
+{
+ find(destination).setCreditMode();
+}
+
+void SemanticState::addByteCredit(const std::string& destination, uint32_t value)
+{
+ ConsumerImpl& c = find(destination);
+ c.addByteCredit(value);
+ requestDispatch(c);
+}
+
+
+void SemanticState::addMessageCredit(const std::string& destination, uint32_t value)
+{
+ ConsumerImpl& c = find(destination);
+ c.addMessageCredit(value);
+ requestDispatch(c);
+}
+
+void SemanticState::flush(const std::string& destination)
+{
+ find(destination).flush();
+}
+
+
+void SemanticState::stop(const std::string& destination)
+{
+ find(destination).stop();
+}
+
+void SemanticState::ConsumerImpl::setWindowMode()
+{
+ windowing = true;
+}
+
+void SemanticState::ConsumerImpl::setCreditMode()
+{
+ windowing = false;
+}
+
+void SemanticState::ConsumerImpl::addByteCredit(uint32_t value)
+{
+ if (byteCredit != 0xFFFFFFFF) {
+ byteCredit += value;
+ }
+}
+
+void SemanticState::ConsumerImpl::addMessageCredit(uint32_t value)
+{
+ if (msgCredit != 0xFFFFFFFF) {
+ msgCredit += value;
+ }
+}
+
+void SemanticState::ConsumerImpl::flush()
+{
+ while(queue->dispatch(shared_from_this()))
+ ;
+ stop();
+}
+
+void SemanticState::ConsumerImpl::stop()
+{
+ msgCredit = 0;
+ byteCredit = 0;
+}
+
+Queue::shared_ptr SemanticState::getQueue(const string& name) const {
+ Queue::shared_ptr queue;
+ if (name.empty()) {
+ throw NotAllowedException(QPID_MSG("No queue name specified."));
+ } else {
+ queue = session.getBroker().getQueues().find(name);
+ if (!queue)
+ throw NotFoundException(QPID_MSG("Queue not found: "<<name));
+ }
+ return queue;
+}
+
+AckRange SemanticState::findRange(DeliveryId first, DeliveryId last)
+{
+ return DeliveryRecord::findRange(unacked, first, last);
+}
+
+void SemanticState::acquire(DeliveryId first, DeliveryId last, DeliveryIds& acquired)
+{
+ AckRange range = findRange(first, last);
+ for_each(range.start, range.end, AcquireFunctor(acquired));
+}
+
+void SemanticState::release(DeliveryId first, DeliveryId last, bool setRedelivered)
+{
+ AckRange range = findRange(first, last);
+ //release results in the message being added to the head so want
+ //to release in reverse order to keep the original transfer order
+ DeliveryRecords::reverse_iterator start(range.end);
+ DeliveryRecords::reverse_iterator end(range.start);
+ for_each(start, end, boost::bind(&DeliveryRecord::release, _1, setRedelivered));
+}
+
+void SemanticState::reject(DeliveryId first, DeliveryId last)
+{
+ AckRange range = findRange(first, last);
+ for_each(range.start, range.end, mem_fun_ref(&DeliveryRecord::reject));
+ //need to remove the delivery records as well
+ unacked.erase(range.start, range.end);
+}
+
+bool SemanticState::ConsumerImpl::hasOutput() {
+ return queue->checkForMessages(shared_from_this());
+}
+
+bool SemanticState::ConsumerImpl::doOutput()
+{
+ return queue->dispatch(shared_from_this());
+}
+
+void SemanticState::ConsumerImpl::enableNotify()
+{
+ Mutex::ScopedLock l(lock);
+ notifyEnabled = true;
+}
+
+void SemanticState::ConsumerImpl::disableNotify()
+{
+ Mutex::ScopedLock l(lock);
+ notifyEnabled = false;
+}
+
+bool SemanticState::ConsumerImpl::isNotifyEnabled() const {
+ Mutex::ScopedLock l(lock);
+ return notifyEnabled;
+}
+
+void SemanticState::ConsumerImpl::notify()
+{
+ //TODO: alter this, don't want to hold locks across external
+ //calls; for now its is required to protect the notify() from
+ //having part of the object chain of the invocation being
+ //concurrently deleted
+ Mutex::ScopedLock l(lock);
+ if (notifyEnabled) parent->outputTasks.activateOutput();
+}
+
+
+void SemanticState::accepted(DeliveryId first, DeliveryId last)
+{
+ AckRange range = findRange(first, last);
+ if (txBuffer.get()) {
+ //in transactional mode, don't dequeue or remove, just
+ //maintain set of acknowledged messages:
+ accumulatedAck.add(first, last);
+
+ if (dtxBuffer.get()) {
+ //if enlisted in a dtx, copy the relevant slice from
+ //unacked and record it against that transaction
+ TxOp::shared_ptr txAck(new DtxAck(accumulatedAck, unacked));
+ accumulatedAck.clear();
+ dtxBuffer->enlist(txAck);
+
+ //mark the relevant messages as 'ended' in unacked
+ for_each(range.start, range.end, mem_fun_ref(&DeliveryRecord::setEnded));
+
+ //if the messages are already completed, they can be
+ //removed from the record
+ unacked.remove_if(mem_fun_ref(&DeliveryRecord::isRedundant));
+
+ }
+ } else {
+ for_each(range.start, range.end, boost::bind(&DeliveryRecord::accept, _1, (TransactionContext*) 0));
+ unacked.remove_if(mem_fun_ref(&DeliveryRecord::isRedundant));
+ }
+}
+
+void SemanticState::completed(DeliveryId first, DeliveryId last)
+{
+ AckRange range = findRange(first, last);
+ for_each(range.start, range.end, boost::bind(&SemanticState::complete, this, _1));
+ unacked.remove_if(mem_fun_ref(&DeliveryRecord::isRedundant));
+ requestDispatch();
+}
+
+void SemanticState::attached()
+{
+ for (ConsumerImplMap::iterator i = consumers.begin(); i != consumers.end(); i++) {
+ i->second->enableNotify();
+ }
+}
+
+void SemanticState::detached()
+{
+ for (ConsumerImplMap::iterator i = consumers.begin(); i != consumers.end(); i++) {
+ i->second->disableNotify();
+ }
+}
+
+}} // namespace qpid::broker
diff --git a/RC9/qpid/cpp/src/qpid/broker/SemanticState.h b/RC9/qpid/cpp/src/qpid/broker/SemanticState.h
new file mode 100644
index 0000000000..340017ddf0
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/SemanticState.h
@@ -0,0 +1,232 @@
+#ifndef QPID_BROKER_SEMANTICSTATE_H
+#define QPID_BROKER_SEMANTICSTATE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Consumer.h"
+#include "Deliverable.h"
+#include "DeliveryAdapter.h"
+#include "DeliveryRecord.h"
+#include "DtxBuffer.h"
+#include "DtxManager.h"
+#include "NameGenerator.h"
+#include "TxBuffer.h"
+
+#include "qpid/framing/FrameHandler.h"
+#include "qpid/framing/SequenceSet.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/sys/AggregateOutput.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/shared_ptr.h"
+#include "AclModule.h"
+
+#include <list>
+#include <map>
+#include <vector>
+
+#include <boost/intrusive_ptr.hpp>
+#include <boost/cast.hpp>
+
+namespace qpid {
+namespace broker {
+
+class SessionContext;
+
+/**
+ * SemanticState holds the L3 and L4 state of an open session, whether
+ * attached to a channel or suspended.
+ */
+class SemanticState : public sys::OutputTask,
+ private boost::noncopyable
+{
+ public:
+ class ConsumerImpl : public Consumer, public sys::OutputTask,
+ public boost::enable_shared_from_this<ConsumerImpl>
+ {
+ mutable qpid::sys::Mutex lock;
+ SemanticState* const parent;
+ const string name;
+ const Queue::shared_ptr queue;
+ const bool ackExpected;
+ const bool acquire;
+ bool blocked;
+ bool windowing;
+ bool exclusive;
+ string resumeId;
+ uint64_t resumeTtl;
+ framing::FieldTable arguments;
+ uint32_t msgCredit;
+ uint32_t byteCredit;
+ bool notifyEnabled;
+
+ bool checkCredit(boost::intrusive_ptr<Message>& msg);
+ void allocateCredit(boost::intrusive_ptr<Message>& msg);
+
+ public:
+ typedef boost::shared_ptr<ConsumerImpl> shared_ptr;
+
+ ConsumerImpl(SemanticState* parent,
+ const string& name, Queue::shared_ptr queue,
+ bool ack, bool acquire, bool exclusive,
+ const std::string& resumeId, uint64_t resumeTtl, const framing::FieldTable& arguments);
+ ~ConsumerImpl();
+ OwnershipToken* getSession();
+ bool deliver(QueuedMessage& msg);
+ bool filter(boost::intrusive_ptr<Message> msg);
+ bool accept(boost::intrusive_ptr<Message> msg);
+
+ void disableNotify();
+ void enableNotify();
+ void notify();
+ bool isNotifyEnabled() const;
+
+ void setWindowMode();
+ void setCreditMode();
+ void addByteCredit(uint32_t value);
+ void addMessageCredit(uint32_t value);
+ void flush();
+ void stop();
+ void complete(DeliveryRecord&);
+ Queue::shared_ptr getQueue() const { return queue; }
+ bool isBlocked() const { return blocked; }
+ bool setBlocked(bool set) { std::swap(set, blocked); return set; }
+
+ bool hasOutput();
+ bool doOutput();
+
+ std::string getName() const { return name; }
+
+ bool isAckExpected() const { return ackExpected; }
+ bool isAcquire() const { return acquire; }
+ bool isWindowing() const { return windowing; }
+ bool isExclusive() const { return exclusive; }
+ uint32_t getMsgCredit() const { return msgCredit; }
+ uint32_t getByteCredit() const { return byteCredit; }
+ std::string getResumeId() const { return resumeId; };
+ uint64_t getResumeTtl() const { return resumeTtl; }
+ const framing::FieldTable& getArguments() const { return arguments; }
+ };
+
+ private:
+ typedef std::map<std::string, ConsumerImpl::shared_ptr> ConsumerImplMap;
+ typedef std::map<std::string, DtxBuffer::shared_ptr> DtxBufferMap;
+
+ SessionContext& session;
+ DeliveryAdapter& deliveryAdapter;
+ ConsumerImplMap consumers;
+ NameGenerator tagGenerator;
+ DeliveryRecords unacked;
+ TxBuffer::shared_ptr txBuffer;
+ DtxBuffer::shared_ptr dtxBuffer;
+ bool dtxSelected;
+ DtxBufferMap suspendedXids;
+ framing::SequenceSet accumulatedAck;
+ boost::shared_ptr<Exchange> cacheExchange;
+ sys::AggregateOutput outputTasks;
+ AclModule* acl;
+ const bool authMsg;
+ const string userID;
+
+ void route(boost::intrusive_ptr<Message> msg, Deliverable& strategy);
+ void checkDtxTimeout();
+
+ void complete(DeliveryRecord&);
+ AckRange findRange(DeliveryId first, DeliveryId last);
+ void requestDispatch();
+ void requestDispatch(ConsumerImpl&);
+ void cancel(ConsumerImpl::shared_ptr);
+
+ public:
+ SemanticState(DeliveryAdapter&, SessionContext&);
+ ~SemanticState();
+
+ SessionContext& getSession() { return session; }
+
+ ConsumerImpl& find(const std::string& destination);
+
+ /**
+ * Get named queue, never returns 0.
+ * @return: named queue
+ * @exception: ChannelException if no queue of that name is found.
+ * @exception: ConnectionException if name="" and session has no default.
+ */
+ Queue::shared_ptr getQueue(const std::string& name) const;
+
+ bool exists(const string& consumerTag);
+
+ void consume(const string& destination,
+ Queue::shared_ptr queue,
+ bool ackRequired, bool acquire, bool exclusive,
+ const string& resumeId=string(), uint64_t resumeTtl=0,
+ const framing::FieldTable& = framing::FieldTable());
+
+ void cancel(const string& tag);
+
+ void setWindowMode(const std::string& destination);
+ void setCreditMode(const std::string& destination);
+ void addByteCredit(const std::string& destination, uint32_t value);
+ void addMessageCredit(const std::string& destination, uint32_t value);
+ void flush(const std::string& destination);
+ void stop(const std::string& destination);
+
+ void startTx();
+ void commit(MessageStore* const store);
+ void rollback();
+ void selectDtx();
+ void startDtx(const std::string& xid, DtxManager& mgr, bool join);
+ void endDtx(const std::string& xid, bool fail);
+ void suspendDtx(const std::string& xid);
+ void resumeDtx(const std::string& xid);
+ void recover(bool requeue);
+ void deliver(DeliveryRecord& message);
+ void acquire(DeliveryId first, DeliveryId last, DeliveryIds& acquired);
+ void release(DeliveryId first, DeliveryId last, bool setRedelivered);
+ void reject(DeliveryId first, DeliveryId last);
+ void handle(boost::intrusive_ptr<Message> msg);
+ bool hasOutput() { return outputTasks.hasOutput(); }
+ bool doOutput() { return outputTasks.doOutput(); }
+
+ //final 0-10 spec (completed and accepted are distinct):
+ void completed(DeliveryId deliveryTag, DeliveryId endTag);
+ void accepted(DeliveryId deliveryTag, DeliveryId endTag);
+
+ void attached();
+ void detached();
+
+ // Used by cluster to re-create replica sessions
+ static ConsumerImpl* castToConsumerImpl(OutputTask* p) { return boost::polymorphic_downcast<ConsumerImpl*>(p); }
+
+ template <class F> void eachConsumer(F f) { outputTasks.eachOutput(boost::bind(f, boost::bind(castToConsumerImpl, _1))); }
+ DeliveryRecords& getUnacked() { return unacked; }
+ framing::SequenceSet getAccumulatedAck() const { return accumulatedAck; }
+ TxBuffer::shared_ptr getTxBuffer() const { return txBuffer; }
+ void setTxBuffer(const TxBuffer::shared_ptr& txb) { txBuffer = txb; }
+ void setAccumulatedAck(const framing::SequenceSet& s) { accumulatedAck = s; }
+ void record(const DeliveryRecord& delivery);
+};
+
+}} // namespace qpid::broker
+
+
+
+
+#endif /*!QPID_BROKER_SEMANTICSTATE_H*/
diff --git a/RC9/qpid/cpp/src/qpid/broker/SessionAdapter.cpp b/RC9/qpid/cpp/src/qpid/broker/SessionAdapter.cpp
new file mode 100644
index 0000000000..4450d56efb
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/SessionAdapter.cpp
@@ -0,0 +1,749 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "SessionAdapter.h"
+#include "Connection.h"
+#include "Queue.h"
+#include "qpid/Exception.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/framing/enum.h"
+#include "qpid/log/Statement.h"
+#include "qpid/framing/SequenceSet.h"
+#include "qpid/agent/ManagementAgent.h"
+#include "qmf/org/apache/qpid/broker/EventExchangeDeclare.h"
+#include "qmf/org/apache/qpid/broker/EventExchangeDelete.h"
+#include "qmf/org/apache/qpid/broker/EventQueueDeclare.h"
+#include "qmf/org/apache/qpid/broker/EventQueueDelete.h"
+#include "qmf/org/apache/qpid/broker/EventBind.h"
+#include "qmf/org/apache/qpid/broker/EventUnbind.h"
+#include "qmf/org/apache/qpid/broker/EventSubscribe.h"
+#include "qmf/org/apache/qpid/broker/EventUnsubscribe.h"
+#include <boost/format.hpp>
+#include <boost/cast.hpp>
+#include <boost/bind.hpp>
+
+namespace qpid {
+namespace broker {
+
+using namespace qpid;
+using namespace qpid::framing;
+using namespace qpid::framing::dtx;
+using namespace qpid::management;
+namespace _qmf = qmf::org::apache::qpid::broker;
+
+typedef std::vector<Queue::shared_ptr> QueueVector;
+
+SessionAdapter::SessionAdapter(SemanticState& s) :
+ HandlerImpl(s),
+ exchangeImpl(s),
+ queueImpl(s),
+ messageImpl(s),
+ executionImpl(s),
+ txImpl(s),
+ dtxImpl(s)
+{}
+
+
+void SessionAdapter::ExchangeHandlerImpl::declare(const string& exchange, const string& type,
+ const string& alternateExchange,
+ bool passive, bool durable, bool /*autoDelete*/, const FieldTable& args){
+
+ AclModule* acl = getBroker().getAcl();
+ if (acl) {
+ std::map<acl::Property, std::string> params;
+ params.insert(make_pair(acl::PROP_TYPE, type));
+ params.insert(make_pair(acl::PROP_ALTERNATE, alternateExchange));
+ params.insert(make_pair(acl::PROP_PASSIVE, std::string(passive ? "true" : "false") ));
+ params.insert(make_pair(acl::PROP_DURABLE, std::string(durable ? "true" : "false")));
+ if (!acl->authorise(getConnection().getUserId(),acl::ACT_CREATE,acl::OBJ_EXCHANGE,exchange,&params) )
+ throw NotAllowedException("ACL denied exhange declare request");
+ }
+
+ //TODO: implement autoDelete
+ Exchange::shared_ptr alternate;
+ if (!alternateExchange.empty()) {
+ alternate = getBroker().getExchanges().get(alternateExchange);
+ }
+ if(passive){
+ Exchange::shared_ptr actual(getBroker().getExchanges().get(exchange));
+ checkType(actual, type);
+ checkAlternate(actual, alternate);
+ }else{
+ try{
+ std::pair<Exchange::shared_ptr, bool> response = getBroker().getExchanges().declare(exchange, type, durable, args);
+ if (response.second) {
+ if (durable) {
+ getBroker().getStore().create(*response.first, args);
+ }
+ if (alternate) {
+ response.first->setAlternate(alternate);
+ alternate->incAlternateUsers();
+ }
+ } else {
+ checkType(response.first, type);
+ checkAlternate(response.first, alternate);
+ }
+
+ ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+ if (agent)
+ agent->raiseEvent(_qmf::EventExchangeDeclare(getConnection().getUrl(), getConnection().getUserId(), exchange, type,
+ alternateExchange, durable, false, args,
+ response.second ? "created" : "existing"));
+
+ }catch(UnknownExchangeTypeException& /*e*/){
+ throw CommandInvalidException(QPID_MSG("Exchange type not implemented: " << type));
+ }
+ }
+}
+
+void SessionAdapter::ExchangeHandlerImpl::checkType(Exchange::shared_ptr exchange, const std::string& type)
+{
+ if (!type.empty() && exchange->getType() != type) {
+ throw NotAllowedException(QPID_MSG("Exchange declared to be of type " << exchange->getType() << ", requested " << type));
+ }
+}
+
+void SessionAdapter::ExchangeHandlerImpl::checkAlternate(Exchange::shared_ptr exchange, Exchange::shared_ptr alternate)
+{
+ if (alternate && alternate != exchange->getAlternate())
+ throw NotAllowedException(QPID_MSG("Exchange declared with alternate-exchange "
+ << exchange->getAlternate()->getName() << ", requested "
+ << alternate->getName()));
+}
+
+void SessionAdapter::ExchangeHandlerImpl::delete_(const string& name, bool /*ifUnused*/)
+{
+ AclModule* acl = getBroker().getAcl();
+ if (acl) {
+ if (!acl->authorise(getConnection().getUserId(),acl::ACT_DELETE,acl::OBJ_EXCHANGE,name,NULL) )
+ throw NotAllowedException("ACL denied exhange delete request");
+ }
+
+ //TODO: implement unused
+ Exchange::shared_ptr exchange(getBroker().getExchanges().get(name));
+ if (exchange->inUseAsAlternate()) throw NotAllowedException(QPID_MSG("Exchange in use as alternate-exchange."));
+ if (exchange->isDurable()) getBroker().getStore().destroy(*exchange);
+ if (exchange->getAlternate()) exchange->getAlternate()->decAlternateUsers();
+ getBroker().getExchanges().destroy(name);
+
+ ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+ if (agent)
+ agent->raiseEvent(_qmf::EventExchangeDelete(getConnection().getUrl(), getConnection().getUserId(), name));
+}
+
+ExchangeQueryResult SessionAdapter::ExchangeHandlerImpl::query(const string& name)
+{
+ AclModule* acl = getBroker().getAcl();
+ if (acl) {
+ if (!acl->authorise(getConnection().getUserId(),acl::ACT_ACCESS,acl::OBJ_EXCHANGE,name,NULL) )
+ throw NotAllowedException("ACL denied exhange query request");
+ }
+
+ try {
+ Exchange::shared_ptr exchange(getBroker().getExchanges().get(name));
+ return ExchangeQueryResult(exchange->getType(), exchange->isDurable(), false, exchange->getArgs());
+ } catch (const NotFoundException& /*e*/) {
+ return ExchangeQueryResult("", false, true, FieldTable());
+ }
+}
+
+void SessionAdapter::ExchangeHandlerImpl::bind(const string& queueName,
+ const string& exchangeName, const string& routingKey,
+ const FieldTable& arguments)
+{
+ AclModule* acl = getBroker().getAcl();
+ if (acl) {
+ if (!acl->authorise(getConnection().getUserId(),acl::ACT_BIND,acl::OBJ_EXCHANGE,exchangeName,routingKey) )
+ throw NotAllowedException("ACL denied exhange bind request");
+ }
+
+ Queue::shared_ptr queue = getQueue(queueName);
+ Exchange::shared_ptr exchange = getBroker().getExchanges().get(exchangeName);
+ if(exchange){
+ string exchangeRoutingKey = routingKey.empty() && queueName.empty() ? queue->getName() : routingKey;
+ if (exchange->bind(queue, exchangeRoutingKey, &arguments)) {
+ queue->bound(exchangeName, routingKey, arguments);
+ if (exchange->isDurable() && queue->isDurable()) {
+ getBroker().getStore().bind(*exchange, *queue, routingKey, arguments);
+ }
+
+ ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+ if (agent)
+ agent->raiseEvent(_qmf::EventBind(getConnection().getUrl(), getConnection().getUserId(), exchangeName, queueName, exchangeRoutingKey, arguments));
+ }
+ }else{
+ throw NotFoundException("Bind failed. No such exchange: " + exchangeName);
+ }
+}
+
+void SessionAdapter::ExchangeHandlerImpl::unbind(const string& queueName,
+ const string& exchangeName,
+ const string& routingKey)
+{
+ AclModule* acl = getBroker().getAcl();
+ if (acl) {
+ std::map<acl::Property, std::string> params;
+ params.insert(make_pair(acl::PROP_QUEUENAME, queueName));
+ params.insert(make_pair(acl::PROP_ROUTINGKEY, routingKey));
+ if (!acl->authorise(getConnection().getUserId(),acl::ACT_UNBIND,acl::OBJ_EXCHANGE,exchangeName,&params) )
+ throw NotAllowedException("ACL denied exchange unbind request");
+ }
+
+ Queue::shared_ptr queue = getQueue(queueName);
+ if (!queue.get()) throw NotFoundException("Unbind failed. No such exchange: " + exchangeName);
+
+ Exchange::shared_ptr exchange = getBroker().getExchanges().get(exchangeName);
+ if (!exchange.get()) throw NotFoundException("Unbind failed. No such exchange: " + exchangeName);
+
+ //TODO: revise unbind to rely solely on binding key (not args)
+ if (exchange->unbind(queue, routingKey, 0)) {
+ if (exchange->isDurable() && queue->isDurable())
+ getBroker().getStore().unbind(*exchange, *queue, routingKey, FieldTable());
+
+ ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+ if (agent)
+ agent->raiseEvent(_qmf::EventUnbind(getConnection().getUrl(), getConnection().getUserId(), exchangeName, queueName, routingKey));
+ }
+}
+
+ExchangeBoundResult SessionAdapter::ExchangeHandlerImpl::bound(const std::string& exchangeName,
+ const std::string& queueName,
+ const std::string& key,
+ const framing::FieldTable& args)
+{
+ AclModule* acl = getBroker().getAcl();
+ if (acl) {
+ std::map<acl::Property, std::string> params;
+ params.insert(make_pair(acl::PROP_QUEUENAME, queueName));
+ params.insert(make_pair(acl::PROP_ROUTINGKEY, key));
+ if (!acl->authorise(getConnection().getUserId(),acl::ACT_CREATE,acl::OBJ_EXCHANGE,exchangeName,&params) )
+ throw NotAllowedException("ACL denied exhange bound request");
+ }
+
+ Exchange::shared_ptr exchange;
+ try {
+ exchange = getBroker().getExchanges().get(exchangeName);
+ } catch (const NotFoundException&) {}
+
+ Queue::shared_ptr queue;
+ if (!queueName.empty()) {
+ queue = getBroker().getQueues().find(queueName);
+ }
+
+ if (!exchange) {
+ return ExchangeBoundResult(true, false, false, false, false);
+ } else if (!queueName.empty() && !queue) {
+ return ExchangeBoundResult(false, true, false, false, false);
+ } else if (exchange->isBound(queue, key.empty() ? 0 : &key, args.count() > 0 ? &args : &args)) {
+ return ExchangeBoundResult(false, false, false, false, false);
+ } else {
+ //need to test each specified option individually
+ bool queueMatched = queueName.empty() || exchange->isBound(queue, 0, 0);
+ bool keyMatched = key.empty() || exchange->isBound(Queue::shared_ptr(), &key, 0);
+ bool argsMatched = args.count() == 0 || exchange->isBound(Queue::shared_ptr(), 0, &args);
+
+ return ExchangeBoundResult(false, false, !queueMatched, !keyMatched, !argsMatched);
+ }
+}
+
+SessionAdapter::QueueHandlerImpl::QueueHandlerImpl(SemanticState& session) : HandlerHelper(session), broker(getBroker())
+{}
+
+
+SessionAdapter::QueueHandlerImpl::~QueueHandlerImpl()
+{
+ try {
+ destroyExclusiveQueues();
+ } catch (std::exception& e) {
+ QPID_LOG(error, e.what());
+ }
+}
+
+void SessionAdapter::QueueHandlerImpl::destroyExclusiveQueues()
+{
+ while (!exclusiveQueues.empty()) {
+ Queue::shared_ptr q(exclusiveQueues.front());
+ q->releaseExclusiveOwnership();
+ if (q->canAutoDelete()) {
+ Queue::tryAutoDelete(broker, q);
+ }
+ exclusiveQueues.erase(exclusiveQueues.begin());
+ }
+}
+
+
+bool SessionAdapter::QueueHandlerImpl::isLocal(const ConnectionToken* t) const
+{
+ return session.isLocal(t);
+}
+
+
+QueueQueryResult SessionAdapter::QueueHandlerImpl::query(const string& name)
+{
+ AclModule* acl = getBroker().getAcl();
+ if (acl) {
+ if (!acl->authorise(getConnection().getUserId(),acl::ACT_ACCESS,acl::OBJ_QUEUE,name,NULL) )
+ throw NotAllowedException("ACL denied queue query request");
+ }
+
+ Queue::shared_ptr queue = session.getBroker().getQueues().find(name);
+ if (queue) {
+
+ Exchange::shared_ptr alternateExchange = queue->getAlternateExchange();
+
+ return QueueQueryResult(queue->getName(),
+ alternateExchange ? alternateExchange->getName() : "",
+ queue->isDurable(),
+ queue->hasExclusiveOwner(),
+ queue->isAutoDelete(),
+ queue->getSettings(),
+ queue->getMessageCount(),
+ queue->getConsumerCount());
+ } else {
+ return QueueQueryResult();
+ }
+}
+
+void SessionAdapter::QueueHandlerImpl::declare(const string& name, const string& alternateExchange,
+ bool passive, bool durable, bool exclusive,
+ bool autoDelete, const qpid::framing::FieldTable& arguments)
+{
+ AclModule* acl = getBroker().getAcl();
+ if (acl) {
+ std::map<acl::Property, std::string> params;
+ params.insert(make_pair(acl::PROP_ALTERNATE, alternateExchange));
+ params.insert(make_pair(acl::PROP_PASSIVE, std::string(passive ? "true" : "false") ));
+ params.insert(make_pair(acl::PROP_DURABLE, std::string(durable ? "true" : "false")));
+ params.insert(make_pair(acl::PROP_EXCLUSIVE, std::string(exclusive ? "true" : "false")));
+ params.insert(make_pair(acl::PROP_AUTODELETE, std::string(autoDelete ? "true" : "false")));
+ if (!acl->authorise(getConnection().getUserId(),acl::ACT_CREATE,acl::OBJ_QUEUE,name,&params) )
+ throw NotAllowedException("ACL denied queue create request");
+ }
+
+ Exchange::shared_ptr alternate;
+ if (!alternateExchange.empty()) {
+ alternate = getBroker().getExchanges().get(alternateExchange);
+ }
+ Queue::shared_ptr queue;
+ if (passive && !name.empty()) {
+ queue = getQueue(name);
+ //TODO: check alternate-exchange is as expected
+ } else {
+ std::pair<Queue::shared_ptr, bool> queue_created =
+ getBroker().getQueues().declare(name, durable,
+ autoDelete,
+ exclusive ? &session : 0);
+ queue = queue_created.first;
+ assert(queue);
+ if (queue_created.second) { // This is a new queue
+ if (alternate) {
+ queue->setAlternateExchange(alternate);
+ alternate->incAlternateUsers();
+ }
+
+ //apply settings & create persistent record if required
+ queue_created.first->create(arguments);
+
+ //add default binding:
+ getBroker().getExchanges().getDefault()->bind(queue, name, 0);
+ queue->bound(getBroker().getExchanges().getDefault()->getName(), name, arguments);
+
+ //handle automatic cleanup:
+ if (exclusive) {
+ exclusiveQueues.push_back(queue);
+ }
+ } else {
+ if (exclusive && queue->setExclusiveOwner(&session)) {
+ exclusiveQueues.push_back(queue);
+ }
+ }
+
+ ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+ if (agent)
+ agent->raiseEvent(_qmf::EventQueueDeclare(getConnection().getUrl(), getConnection().getUserId(),
+ name, durable, exclusive, autoDelete, arguments,
+ queue_created.second ? "created" : "existing"));
+ }
+
+ if (exclusive && !queue->isExclusiveOwner(&session))
+ throw ResourceLockedException(QPID_MSG("Cannot grant exclusive access to queue "
+ << queue->getName()));
+}
+
+
+void SessionAdapter::QueueHandlerImpl::purge(const string& queue){
+ AclModule* acl = getBroker().getAcl();
+ if (acl)
+ {
+ if (!acl->authorise(getConnection().getUserId(),acl::ACT_PURGE,acl::OBJ_QUEUE,queue,NULL) )
+ throw NotAllowedException("ACL denied queue purge request");
+ }
+ getQueue(queue)->purge();
+}
+
+void SessionAdapter::QueueHandlerImpl::delete_(const string& queue, bool ifUnused, bool ifEmpty){
+
+ AclModule* acl = getBroker().getAcl();
+ if (acl)
+ {
+ if (!acl->authorise(getConnection().getUserId(),acl::ACT_DELETE,acl::OBJ_QUEUE,queue,NULL) )
+ throw NotAllowedException("ACL denied queue delete request");
+ }
+
+ Queue::shared_ptr q = getQueue(queue);
+ if (q->hasExclusiveOwner() && !q->isExclusiveOwner(&session))
+ throw ResourceLockedException(QPID_MSG("Cannot delete queue "
+ << queue << "; it is exclusive to another session"));
+ if(ifEmpty && q->getMessageCount() > 0){
+ throw PreconditionFailedException("Queue not empty.");
+ }else if(ifUnused && q->getConsumerCount() > 0){
+ throw PreconditionFailedException("Queue in use.");
+ }else{
+ //remove the queue from the list of exclusive queues if necessary
+ if(q->isExclusiveOwner(&getConnection())){
+ QueueVector::iterator i = std::find(getConnection().exclusiveQueues.begin(), getConnection().exclusiveQueues.end(), q);
+ if(i < getConnection().exclusiveQueues.end()) getConnection().exclusiveQueues.erase(i);
+ }
+ q->destroy();
+ getBroker().getQueues().destroy(queue);
+ q->unbind(getBroker().getExchanges(), q);
+
+ ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+ if (agent)
+ agent->raiseEvent(_qmf::EventQueueDelete(getConnection().getUrl(), getConnection().getUserId(), queue));
+ }
+}
+
+
+SessionAdapter::MessageHandlerImpl::MessageHandlerImpl(SemanticState& s) :
+ HandlerHelper(s),
+ releaseRedeliveredOp(boost::bind(&SemanticState::release, &state, _1, _2, true)),
+ releaseOp(boost::bind(&SemanticState::release, &state, _1, _2, false)),
+ rejectOp(boost::bind(&SemanticState::reject, &state, _1, _2)),
+ acceptOp(boost::bind(&SemanticState::accepted, &state, _1, _2))
+ {}
+
+//
+// Message class method handlers
+//
+
+void SessionAdapter::MessageHandlerImpl::transfer(const string& /*destination*/,
+ uint8_t /*acceptMode*/,
+ uint8_t /*acquireMode*/)
+{
+ //not yet used (content containing assemblies treated differently at present
+ std::cout << "SessionAdapter::MessageHandlerImpl::transfer() called" << std::endl;
+}
+
+void SessionAdapter::MessageHandlerImpl::release(const SequenceSet& transfers, bool setRedelivered)
+{
+ transfers.for_each(setRedelivered ? releaseRedeliveredOp : releaseOp);
+}
+
+void
+SessionAdapter::MessageHandlerImpl::subscribe(const string& queueName,
+ const string& destination,
+ uint8_t acceptMode,
+ uint8_t acquireMode,
+ bool exclusive,
+ const string& resumeId,
+ uint64_t resumeTtl,
+ const FieldTable& arguments)
+{
+
+ AclModule* acl = getBroker().getAcl();
+ if (acl)
+ {
+ // add flags as needed
+ if (!acl->authorise(getConnection().getUserId(),acl::ACT_CONSUME,acl::OBJ_QUEUE,queueName,NULL) )
+ throw NotAllowedException("ACL denied Queue subscribe request");
+ }
+
+ Queue::shared_ptr queue = getQueue(queueName);
+ if(!destination.empty() && state.exists(destination))
+ throw NotAllowedException(QPID_MSG("Consumer tags must be unique"));
+ if (queue->hasExclusiveOwner() && !queue->isExclusiveOwner(&session))
+ throw ResourceLockedException(QPID_MSG("Cannot subscribe to exclusive queue "
+ << queue->getName()));
+
+ state.consume(destination, queue,
+ acceptMode == 0, acquireMode == 0, exclusive,
+ resumeId, resumeTtl, arguments);
+
+ ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+ if (agent)
+ agent->raiseEvent(_qmf::EventSubscribe(getConnection().getUrl(), getConnection().getUserId(),
+ queueName, destination, exclusive, arguments));
+}
+
+void
+SessionAdapter::MessageHandlerImpl::cancel(const string& destination )
+{
+ state.cancel(destination);
+
+ ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+ if (agent)
+ agent->raiseEvent(_qmf::EventUnsubscribe(getConnection().getUrl(), getConnection().getUserId(), destination));
+}
+
+void
+SessionAdapter::MessageHandlerImpl::reject(const SequenceSet& transfers, uint16_t /*code*/, const string& /*text*/ )
+{
+ transfers.for_each(rejectOp);
+}
+
+void SessionAdapter::MessageHandlerImpl::flow(const std::string& destination, uint8_t unit, uint32_t value)
+{
+ if (unit == 0) {
+ //message
+ state.addMessageCredit(destination, value);
+ } else if (unit == 1) {
+ //bytes
+ state.addByteCredit(destination, value);
+ } else {
+ //unknown
+ throw InvalidArgumentException(QPID_MSG("Invalid value for unit " << unit));
+ }
+
+}
+
+void SessionAdapter::MessageHandlerImpl::setFlowMode(const std::string& destination, uint8_t mode)
+{
+ if (mode == 0) {
+ //credit
+ state.setCreditMode(destination);
+ } else if (mode == 1) {
+ //window
+ state.setWindowMode(destination);
+ } else{
+ throw InvalidArgumentException(QPID_MSG("Invalid value for mode " << mode));
+ }
+}
+
+void SessionAdapter::MessageHandlerImpl::flush(const std::string& destination)
+{
+ state.flush(destination);
+}
+
+void SessionAdapter::MessageHandlerImpl::stop(const std::string& destination)
+{
+ state.stop(destination);
+}
+
+void SessionAdapter::MessageHandlerImpl::accept(const framing::SequenceSet& commands)
+{
+
+ commands.for_each(acceptOp);
+}
+
+framing::MessageAcquireResult SessionAdapter::MessageHandlerImpl::acquire(const framing::SequenceSet& transfers)
+{
+ // FIXME aconway 2008-05-12: create SequenceSet directly, no need for intermediate results vector.
+ SequenceNumberSet results;
+ RangedOperation f = boost::bind(&SemanticState::acquire, &state, _1, _2, boost::ref(results));
+ transfers.for_each(f);
+
+ results = results.condense();
+ SequenceSet acquisitions;
+ RangedOperation g = boost::bind(&SequenceSet::add, &acquisitions, _1, _2);
+ results.processRanges(g);
+
+ return MessageAcquireResult(acquisitions);
+}
+
+framing::MessageResumeResult SessionAdapter::MessageHandlerImpl::resume(const std::string& /*destination*/,
+ const std::string& /*resumeId*/)
+{
+ throw NotImplementedException("resuming transfers not yet supported");
+}
+
+
+
+void SessionAdapter::ExecutionHandlerImpl::sync() {} //essentially a no-op
+
+void SessionAdapter::ExecutionHandlerImpl::result(const SequenceNumber& /*commandId*/, const string& /*value*/)
+{
+ //TODO: but currently never used client->server
+}
+
+void SessionAdapter::ExecutionHandlerImpl::exception(uint16_t /*errorCode*/,
+ const SequenceNumber& /*commandId*/,
+ uint8_t /*classCode*/,
+ uint8_t /*commandCode*/,
+ uint8_t /*fieldIndex*/,
+ const std::string& /*description*/,
+ const framing::FieldTable& /*errorInfo*/)
+{
+ //TODO: again, not really used client->server but may be important
+ //for inter-broker links
+}
+
+
+
+void SessionAdapter::TxHandlerImpl::select()
+{
+ state.startTx();
+}
+
+void SessionAdapter::TxHandlerImpl::commit()
+{
+ state.commit(&getBroker().getStore());
+}
+
+void SessionAdapter::TxHandlerImpl::rollback()
+{
+ state.rollback();
+}
+
+std::string SessionAdapter::DtxHandlerImpl::convert(const framing::Xid& xid)
+{
+ std::string encoded;
+ encode(xid, encoded);
+ return encoded;
+}
+
+void SessionAdapter::DtxHandlerImpl::select()
+{
+ state.selectDtx();
+}
+
+XaResult SessionAdapter::DtxHandlerImpl::end(const Xid& xid,
+ bool fail,
+ bool suspend)
+{
+ try {
+ if (fail) {
+ state.endDtx(convert(xid), true);
+ if (suspend) {
+ throw CommandInvalidException(QPID_MSG("End and suspend cannot both be set."));
+ } else {
+ return XaResult(XA_STATUS_XA_RBROLLBACK);
+ }
+ } else {
+ if (suspend) {
+ state.suspendDtx(convert(xid));
+ } else {
+ state.endDtx(convert(xid), false);
+ }
+ return XaResult(XA_STATUS_XA_OK);
+ }
+ } catch (const DtxTimeoutException& /*e*/) {
+ return XaResult(XA_STATUS_XA_RBTIMEOUT);
+ }
+}
+
+XaResult SessionAdapter::DtxHandlerImpl::start(const Xid& xid,
+ bool join,
+ bool resume)
+{
+ if (join && resume) {
+ throw CommandInvalidException(QPID_MSG("Join and resume cannot both be set."));
+ }
+ try {
+ if (resume) {
+ state.resumeDtx(convert(xid));
+ } else {
+ state.startDtx(convert(xid), getBroker().getDtxManager(), join);
+ }
+ return XaResult(XA_STATUS_XA_OK);
+ } catch (const DtxTimeoutException& /*e*/) {
+ return XaResult(XA_STATUS_XA_RBTIMEOUT);
+ }
+}
+
+XaResult SessionAdapter::DtxHandlerImpl::prepare(const Xid& xid)
+{
+ try {
+ bool ok = getBroker().getDtxManager().prepare(convert(xid));
+ return XaResult(ok ? XA_STATUS_XA_OK : XA_STATUS_XA_RBROLLBACK);
+ } catch (const DtxTimeoutException& /*e*/) {
+ return XaResult(XA_STATUS_XA_RBTIMEOUT);
+ }
+}
+
+XaResult SessionAdapter::DtxHandlerImpl::commit(const Xid& xid,
+ bool onePhase)
+{
+ try {
+ bool ok = getBroker().getDtxManager().commit(convert(xid), onePhase);
+ return XaResult(ok ? XA_STATUS_XA_OK : XA_STATUS_XA_RBROLLBACK);
+ } catch (const DtxTimeoutException& /*e*/) {
+ return XaResult(XA_STATUS_XA_RBTIMEOUT);
+ }
+}
+
+
+XaResult SessionAdapter::DtxHandlerImpl::rollback(const Xid& xid)
+{
+ try {
+ getBroker().getDtxManager().rollback(convert(xid));
+ return XaResult(XA_STATUS_XA_OK);
+ } catch (const DtxTimeoutException& /*e*/) {
+ return XaResult(XA_STATUS_XA_RBTIMEOUT);
+ }
+}
+
+DtxRecoverResult SessionAdapter::DtxHandlerImpl::recover()
+{
+ std::set<std::string> xids;
+ getBroker().getStore().collectPreparedXids(xids);
+ /*
+ * create array of long structs
+ */
+ Array indoubt(0xAB);
+ for (std::set<std::string>::iterator i = xids.begin(); i != xids.end(); i++) {
+ boost::shared_ptr<FieldValue> xid(new Struct32Value(*i));
+ indoubt.add(xid);
+ }
+ return DtxRecoverResult(indoubt);
+}
+
+void SessionAdapter::DtxHandlerImpl::forget(const Xid& xid)
+{
+ //Currently no heuristic completion is supported, so this should never be used.
+ throw NotImplementedException(QPID_MSG("Forget not implemented. Branch with xid " << xid << " not heuristically completed!"));
+}
+
+DtxGetTimeoutResult SessionAdapter::DtxHandlerImpl::getTimeout(const Xid& xid)
+{
+ uint32_t timeout = getBroker().getDtxManager().getTimeout(convert(xid));
+ return DtxGetTimeoutResult(timeout);
+}
+
+
+void SessionAdapter::DtxHandlerImpl::setTimeout(const Xid& xid,
+ uint32_t timeout)
+{
+ getBroker().getDtxManager().setTimeout(convert(xid), timeout);
+}
+
+
+Queue::shared_ptr SessionAdapter::HandlerHelper::getQueue(const string& name) const {
+ Queue::shared_ptr queue;
+ if (name.empty()) {
+ throw framing::IllegalArgumentException(QPID_MSG("No queue name specified."));
+ } else {
+ queue = session.getBroker().getQueues().find(name);
+ if (!queue)
+ throw framing::NotFoundException(QPID_MSG("Queue not found: "<<name));
+ }
+ return queue;
+}
+
+}} // namespace qpid::broker
+
+
diff --git a/RC9/qpid/cpp/src/qpid/broker/SessionAdapter.h b/RC9/qpid/cpp/src/qpid/broker/SessionAdapter.h
new file mode 100644
index 0000000000..60a5a0f285
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/SessionAdapter.h
@@ -0,0 +1,260 @@
+#ifndef _broker_SessionAdapter_h
+#define _broker_SessionAdapter_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "HandlerImpl.h"
+
+#include "ConnectionToken.h"
+#include "OwnershipToken.h"
+#include "qpid/Exception.h"
+#include "qpid/framing/AMQP_ServerOperations.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/framing/StructHelper.h"
+
+#include <vector>
+#include <boost/function.hpp>
+#include <boost/shared_ptr.hpp>
+
+namespace qpid {
+namespace broker {
+
+class Channel;
+class Connection;
+class Broker;
+class Queue;
+
+/**
+ * Per-channel protocol adapter.
+ *
+ * A container for a collection of AMQP-class adapters that translate
+ * AMQP method bodies into calls on the core Broker objects. Each
+ * adapter class also provides a client proxy to send methods to the
+ * peer.
+ *
+ */
+ class SessionAdapter : public HandlerImpl, public framing::AMQP_ServerOperations
+{
+ public:
+ SessionAdapter(SemanticState& session);
+
+ framing::ProtocolVersion getVersion() const { return session.getConnection().getVersion();}
+
+ MessageHandler* getMessageHandler(){ return &messageImpl; }
+ ExchangeHandler* getExchangeHandler(){ return &exchangeImpl; }
+ QueueHandler* getQueueHandler(){ return &queueImpl; }
+ ExecutionHandler* getExecutionHandler(){ return &executionImpl; }
+ TxHandler* getTxHandler(){ return &txImpl; }
+ DtxHandler* getDtxHandler(){ return &dtxImpl; }
+
+ ConnectionHandler* getConnectionHandler() { throw framing::NotImplementedException("Class not implemented"); }
+ SessionHandler* getSessionHandler() { throw framing::NotImplementedException("Class not implemented"); }
+ FileHandler* getFileHandler() { throw framing::NotImplementedException("Class not implemented"); }
+ StreamHandler* getStreamHandler() { throw framing::NotImplementedException("Class not implemented"); }
+
+ private:
+ //common base for utility methods etc that are specific to this adapter
+ struct HandlerHelper : public HandlerImpl
+ {
+ HandlerHelper(SemanticState& s) : HandlerImpl(s) {}
+
+ Queue::shared_ptr getQueue(const string& name) const;
+ };
+
+
+ class ExchangeHandlerImpl :
+ public ExchangeHandler,
+ public HandlerHelper
+ {
+ public:
+ ExchangeHandlerImpl(SemanticState& session) : HandlerHelper(session) {}
+
+ void declare(const std::string& exchange, const std::string& type,
+ const std::string& alternateExchange,
+ bool passive, bool durable, bool autoDelete,
+ const qpid::framing::FieldTable& arguments);
+ void delete_(const std::string& exchange, bool ifUnused);
+ framing::ExchangeQueryResult query(const std::string& name);
+ void bind(const std::string& queue,
+ const std::string& exchange, const std::string& routingKey,
+ const qpid::framing::FieldTable& arguments);
+ void unbind(const std::string& queue,
+ const std::string& exchange,
+ const std::string& routingKey);
+ framing::ExchangeBoundResult bound(const std::string& exchange,
+ const std::string& queue,
+ const std::string& routingKey,
+ const framing::FieldTable& arguments);
+ private:
+ void checkType(shared_ptr<Exchange> exchange, const std::string& type);
+
+ void checkAlternate(shared_ptr<Exchange> exchange,
+ shared_ptr<Exchange> alternate);
+ };
+
+ class QueueHandlerImpl : public QueueHandler,
+ public HandlerHelper
+ {
+ Broker& broker;
+ std::vector< boost::shared_ptr<Queue> > exclusiveQueues;
+
+ public:
+ QueueHandlerImpl(SemanticState& session);
+ ~QueueHandlerImpl();
+
+ void declare(const std::string& queue,
+ const std::string& alternateExchange,
+ bool passive, bool durable, bool exclusive,
+ bool autoDelete,
+ const qpid::framing::FieldTable& arguments);
+ void delete_(const std::string& queue,
+ bool ifUnused, bool ifEmpty);
+ void purge(const std::string& queue);
+ framing::QueueQueryResult query(const std::string& queue);
+ bool isLocal(const ConnectionToken* t) const;
+
+ void destroyExclusiveQueues();
+ };
+
+ class MessageHandlerImpl :
+ public MessageHandler,
+ public HandlerHelper
+ {
+ typedef boost::function<void(DeliveryId, DeliveryId)> RangedOperation;
+ RangedOperation releaseRedeliveredOp;
+ RangedOperation releaseOp;
+ RangedOperation rejectOp;
+ RangedOperation acceptOp;
+
+ public:
+ MessageHandlerImpl(SemanticState& session);
+ void transfer(const string& destination,
+ uint8_t acceptMode,
+ uint8_t acquireMode);
+
+ void accept(const framing::SequenceSet& commands);
+
+ void reject(const framing::SequenceSet& commands,
+ uint16_t code,
+ const string& text);
+
+ void release(const framing::SequenceSet& commands,
+ bool setRedelivered);
+
+ framing::MessageAcquireResult acquire(const framing::SequenceSet&);
+
+ void subscribe(const string& queue,
+ const string& destination,
+ uint8_t acceptMode,
+ uint8_t acquireMode,
+ bool exclusive,
+ const string& resumeId,
+ uint64_t resumeTtl,
+ const framing::FieldTable& arguments);
+
+ void cancel(const string& destination);
+
+ void setFlowMode(const string& destination,
+ uint8_t flowMode);
+
+ void flow(const string& destination,
+ uint8_t unit,
+ uint32_t value);
+
+ void flush(const string& destination);
+
+ void stop(const string& destination);
+
+ framing::MessageResumeResult resume(const std::string& destination,
+ const std::string& resumeId);
+
+ };
+
+ class ExecutionHandlerImpl : public ExecutionHandler, public HandlerHelper
+ {
+ public:
+ ExecutionHandlerImpl(SemanticState& session) : HandlerHelper(session) {}
+
+ void sync();
+ void result(const framing::SequenceNumber& commandId, const string& value);
+ void exception(uint16_t errorCode,
+ const framing::SequenceNumber& commandId,
+ uint8_t classCode,
+ uint8_t commandCode,
+ uint8_t fieldIndex,
+ const std::string& description,
+ const framing::FieldTable& errorInfo);
+
+ };
+
+ class TxHandlerImpl : public TxHandler, public HandlerHelper
+ {
+ public:
+ TxHandlerImpl(SemanticState& session) : HandlerHelper(session) {}
+
+ void select();
+ void commit();
+ void rollback();
+ };
+
+ class DtxHandlerImpl : public DtxHandler, public HandlerHelper, private framing::StructHelper
+ {
+ std::string convert(const framing::Xid& xid);
+
+ public:
+ DtxHandlerImpl(SemanticState& session) : HandlerHelper(session) {}
+
+ void select();
+
+ framing::XaResult start(const framing::Xid& xid,
+ bool join,
+ bool resume);
+
+ framing::XaResult end(const framing::Xid& xid,
+ bool fail,
+ bool suspend);
+
+ framing::XaResult commit(const framing::Xid& xid,
+ bool onePhase);
+
+ void forget(const framing::Xid& xid);
+
+ framing::DtxGetTimeoutResult getTimeout(const framing::Xid& xid);
+
+ framing::XaResult prepare(const framing::Xid& xid);
+
+ framing::DtxRecoverResult recover();
+
+ framing::XaResult rollback(const framing::Xid& xid);
+
+ void setTimeout(const framing::Xid& xid, uint32_t timeout);
+ };
+
+ ExchangeHandlerImpl exchangeImpl;
+ QueueHandlerImpl queueImpl;
+ MessageHandlerImpl messageImpl;
+ ExecutionHandlerImpl executionImpl;
+ TxHandlerImpl txImpl;
+ DtxHandlerImpl dtxImpl;
+};
+}} // namespace qpid::broker
+
+
+
+#endif /*!_broker_SessionAdapter_h*/
diff --git a/RC9/qpid/cpp/src/qpid/broker/SessionContext.h b/RC9/qpid/cpp/src/qpid/broker/SessionContext.h
new file mode 100644
index 0000000000..7a277964ab
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/SessionContext.h
@@ -0,0 +1,52 @@
+#ifndef QPID_BROKER_SESSIONCONTEXT_H
+#define QPID_BROKER_SESSIONCONTEXT_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/framing/FrameHandler.h"
+#include "qpid/framing/AMQP_ClientProxy.h"
+#include "qpid/framing/amqp_types.h"
+#include "qpid/sys/OutputControl.h"
+#include "ConnectionState.h"
+#include "OwnershipToken.h"
+
+
+#include <boost/noncopyable.hpp>
+
+namespace qpid {
+namespace broker {
+
+class SessionContext : public OwnershipToken, public sys::OutputControl
+{
+ public:
+ virtual ~SessionContext(){}
+ virtual bool isLocal(const ConnectionToken* t) const = 0;
+ virtual ConnectionState& getConnection() = 0;
+ virtual framing::AMQP_ClientProxy& getProxy() = 0;
+ virtual Broker& getBroker() = 0;
+};
+
+}} // namespace qpid::broker
+
+
+
+#endif /*!QPID_BROKER_SESSIONCONTEXT_H*/
diff --git a/RC9/qpid/cpp/src/qpid/broker/SessionHandler.cpp b/RC9/qpid/cpp/src/qpid/broker/SessionHandler.cpp
new file mode 100644
index 0000000000..163102d008
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/SessionHandler.cpp
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "SessionHandler.h"
+#include "SessionState.h"
+#include "Connection.h"
+#include "qpid/log/Statement.h"
+
+#include <boost/bind.hpp>
+
+namespace qpid {
+namespace broker {
+using namespace framing;
+using namespace std;
+using namespace qpid::sys;
+
+SessionHandler::SessionHandler(Connection& c, ChannelId ch)
+ : amqp_0_10::SessionHandler(&c.getOutput(), ch),
+ connection(c),
+ proxy(out)
+{}
+
+SessionHandler::~SessionHandler() {}
+
+namespace {
+ClassId classId(AMQMethodBody* m) { return m ? m->amqpMethodId() : 0; }
+MethodId methodId(AMQMethodBody* m) { return m ? m->amqpClassId() : 0; }
+} // namespace
+
+void SessionHandler::channelException(framing::session::DetachCode, const std::string&) {
+ handleDetach();
+}
+
+void SessionHandler::connectionException(framing::connection::CloseCode code, const std::string& msg) {
+ connection.close(code, msg);
+}
+
+ConnectionState& SessionHandler::getConnection() { return connection; }
+
+const ConnectionState& SessionHandler::getConnection() const { return connection; }
+
+void SessionHandler::handleDetach() {
+ amqp_0_10::SessionHandler::handleDetach();
+ assert(&connection.getChannel(channel.get()) == this);
+ if (session.get())
+ connection.getBroker().getSessionManager().detach(session);
+ assert(!session.get());
+ connection.closeChannel(channel.get());
+}
+
+void SessionHandler::setState(const std::string& name, bool force) {
+ assert(!session.get());
+ SessionId id(connection.getUserId(), name);
+ session = connection.broker.getSessionManager().attach(*this, id, force);
+}
+
+void SessionHandler::detaching()
+{
+ assert(session.get());
+ session->disableOutput();
+}
+
+FrameHandler* SessionHandler::getInHandler() { return session.get() ? &session->in : 0; }
+qpid::SessionState* SessionHandler::getState() { return session.get(); }
+
+void SessionHandler::readyToSend() {
+ if (session.get()) session->readyToSend();
+}
+
+// TODO aconway 2008-05-12: hacky - handle attached for bridge clients.
+// We need to integrate the client code so we can run a real client
+// in the bridge.
+//
+void SessionHandler::attached(const std::string& name) {
+ if (session.get())
+ checkName(name);
+ else {
+ SessionId id(connection.getUserId(), name);
+ SessionState::Configuration config = connection.broker.getSessionManager().getSessionConfig();
+ session.reset(new SessionState(connection.getBroker(), *this, id, config));
+}
+}
+
+}} // namespace qpid::broker
diff --git a/RC9/qpid/cpp/src/qpid/broker/SessionHandler.h b/RC9/qpid/cpp/src/qpid/broker/SessionHandler.h
new file mode 100644
index 0000000000..7449db1560
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/SessionHandler.h
@@ -0,0 +1,81 @@
+#ifndef QPID_BROKER_SESSIONHANDLER_H
+#define QPID_BROKER_SESSIONHANDLER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/amqp_0_10/SessionHandler.h"
+#include "qpid/framing/AMQP_ClientProxy.h"
+
+namespace qpid {
+class SessionState;
+
+namespace broker {
+
+class Connection;
+class ConnectionState;
+class SessionState;
+
+/**
+ * A SessionHandler is associated with each active channel. It
+ * receives incoming frames, handles session controls and manages the
+ * association between the channel and a session.
+ */
+class SessionHandler : public amqp_0_10::SessionHandler {
+ public:
+ SessionHandler(Connection&, framing::ChannelId);
+ ~SessionHandler();
+
+ /** Get broker::SessionState */
+ SessionState* getSession() { return session.get(); }
+ const SessionState* getSession() const { return session.get(); }
+
+ ConnectionState& getConnection();
+ const ConnectionState& getConnection() const;
+
+ framing::AMQP_ClientProxy& getProxy() { return proxy; }
+ const framing::AMQP_ClientProxy& getProxy() const { return proxy; }
+
+ virtual void handleDetach();
+
+ // Overrides
+ void attached(const std::string& name);
+
+ protected:
+ virtual void setState(const std::string& sessionName, bool force);
+ virtual qpid::SessionState* getState();
+ virtual framing::FrameHandler* getInHandler();
+ virtual void channelException(framing::session::DetachCode code, const std::string& msg);
+ virtual void connectionException(framing::connection::CloseCode code, const std::string& msg);
+ virtual void detaching();
+ virtual void readyToSend();
+
+ private:
+ Connection& connection;
+ framing::AMQP_ClientProxy proxy;
+ std::auto_ptr<SessionState> session;
+};
+
+}} // namespace qpid::broker
+
+
+
+#endif /*!QPID_BROKER_SESSIONHANDLER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/broker/SessionManager.cpp b/RC9/qpid/cpp/src/qpid/broker/SessionManager.cpp
new file mode 100644
index 0000000000..a35488b746
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/SessionManager.cpp
@@ -0,0 +1,104 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "SessionManager.h"
+#include "SessionState.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/log/Statement.h"
+#include "qpid/log/Helpers.h"
+#include "qpid/memory.h"
+
+#include <boost/bind.hpp>
+#include <boost/range.hpp>
+
+#include <algorithm>
+#include <functional>
+#include <ostream>
+
+namespace qpid {
+namespace broker {
+
+using boost::intrusive_ptr;
+using namespace sys;
+using namespace framing;
+
+SessionManager::SessionManager(const SessionState::Configuration& c, Broker& b)
+ : config(c), broker(b) {}
+
+SessionManager::~SessionManager() {
+ detached.clear(); // Must clear before destructor as session dtor will call forget()
+}
+
+std::auto_ptr<SessionState> SessionManager::attach(SessionHandler& h, const SessionId& id, bool/*force*/) {
+ Mutex::ScopedLock l(lock);
+ eraseExpired(); // Clean up expired table
+ std::pair<Attached::iterator, bool> insert = attached.insert(id);
+ if (!insert.second)
+ throw SessionBusyException(QPID_MSG("Session already attached: " << id));
+ Detached::iterator i = std::find(detached.begin(), detached.end(), id);
+ std::auto_ptr<SessionState> state;
+ if (i == detached.end())
+ state.reset(new SessionState(broker, h, id, config));
+ else {
+ state.reset(detached.release(i).release());
+ state->attach(h);
+ }
+ return state;
+ // FIXME aconway 2008-04-29: implement force
+}
+
+void SessionManager::detach(std::auto_ptr<SessionState> session) {
+ Mutex::ScopedLock l(lock);
+ attached.erase(session->getId());
+ session->detach();
+ if (session->getTimeout() > 0) {
+ session->expiry = AbsTime(now(),session->getTimeout()*TIME_SEC);
+ if (session->mgmtObject != 0)
+ session->mgmtObject->set_expireTime ((uint64_t) Duration (session->expiry));
+ detached.push_back(session.release()); // In expiry order
+ eraseExpired();
+}
+}
+
+void SessionManager::forget(const SessionId& id) {
+ Mutex::ScopedLock l(lock);
+ attached.erase(id);
+}
+
+void SessionManager::eraseExpired() {
+ // Called with lock held.
+ if (!detached.empty()) {
+ // This used to use a more elegant invocation of std::lower_bound
+ // but violated the strict weak ordering rule which Visual Studio
+ // enforced. See QPID-1424 for more info should you be tempted to
+ // replace the loop with something more elegant.
+ AbsTime now = AbsTime::now();
+ Detached::iterator keep = detached.begin();
+ while ((keep != detached.end()) && ((*keep).expiry < now))
+ keep++;
+ if (detached.begin() != keep) {
+ QPID_LOG(debug, "Expiring sessions: " << log::formatList(detached.begin(), keep));
+ detached.erase(detached.begin(), keep);
+ }
+ }
+}
+
+}} // namespace qpid::broker
diff --git a/RC9/qpid/cpp/src/qpid/broker/SessionManager.h b/RC9/qpid/cpp/src/qpid/broker/SessionManager.h
new file mode 100644
index 0000000000..db88e7ec10
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/SessionManager.h
@@ -0,0 +1,87 @@
+#ifndef QPID_BROKER_SESSIONMANAGER_H
+#define QPID_BROKER_SESSIONMANAGER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/SessionState.h>
+#include <qpid/sys/Time.h>
+#include <qpid/sys/Mutex.h>
+#include <qpid/RefCounted.h>
+
+#include <set>
+#include <vector>
+#include <memory>
+
+#include <boost/noncopyable.hpp>
+#include <boost/ptr_container/ptr_vector.hpp>
+#include <boost/intrusive_ptr.hpp>
+
+namespace qpid {
+namespace broker {
+class Broker;
+class SessionState;
+class SessionHandler;
+
+/**
+ * Create and manage SessionState objects.
+ */
+class SessionManager : private boost::noncopyable {
+ public:
+ SessionManager(const qpid::SessionState::Configuration&, Broker&);
+
+ ~SessionManager();
+
+ /** Open a new active session, caller takes ownership */
+ std::auto_ptr<SessionState> attach(SessionHandler& h, const SessionId& id, bool/*force*/);
+
+ /** Return a detached session to the manager, start the timeout counter. */
+ void detach(std::auto_ptr<SessionState>);
+
+ /** Forget about an attached session. Called by SessionState destructor. */
+ void forget(const SessionId&);
+
+ Broker& getBroker() const { return broker; }
+
+ const qpid::SessionState::Configuration& getSessionConfig() const { return config; }
+
+ private:
+ typedef boost::ptr_vector<SessionState> Detached; // Sorted in expiry order.
+ typedef std::set<SessionId> Attached;
+
+ void eraseExpired();
+
+ sys::Mutex lock;
+ Detached detached;
+ Attached attached;
+ qpid::SessionState::Configuration config;
+ Broker& broker;
+};
+
+
+
+}} // namespace qpid::broker
+
+
+
+
+
+#endif /*!QPID_BROKER_SESSIONMANAGER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/broker/SessionState.cpp b/RC9/qpid/cpp/src/qpid/broker/SessionState.cpp
new file mode 100644
index 0000000000..4f088fdf4c
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/SessionState.cpp
@@ -0,0 +1,271 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "SessionState.h"
+#include "Broker.h"
+#include "ConnectionState.h"
+#include "DeliveryRecord.h"
+#include "SessionManager.h"
+#include "SessionHandler.h"
+#include "qpid/framing/AMQContentBody.h"
+#include "qpid/framing/AMQHeaderBody.h"
+#include "qpid/framing/AMQMethodBody.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/framing/ServerInvoker.h"
+#include "qpid/log/Statement.h"
+
+#include <boost/bind.hpp>
+#include <boost/lexical_cast.hpp>
+
+namespace qpid {
+namespace broker {
+
+using namespace framing;
+using sys::Mutex;
+using boost::intrusive_ptr;
+using qpid::management::ManagementAgent;
+using qpid::management::ManagementObject;
+using qpid::management::Manageable;
+using qpid::management::Args;
+namespace _qmf = qmf::org::apache::qpid::broker;
+
+SessionState::SessionState(
+ Broker& b, SessionHandler& h, const SessionId& id, const SessionState::Configuration& config)
+ : qpid::SessionState(id, config),
+ broker(b), handler(&h),
+ semanticState(*this, *this),
+ adapter(semanticState),
+ msgBuilder(&broker.getStore(), broker.getStagingThreshold()),
+ enqueuedOp(boost::bind(&SessionState::enqueued, this, _1)),
+ mgmtObject(0)
+{
+ Manageable* parent = broker.GetVhostObject ();
+ if (parent != 0) {
+ ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+ if (agent != 0) {
+ mgmtObject = new _qmf::Session
+ (agent, this, parent, getId().getName());
+ mgmtObject->set_attached (0);
+ mgmtObject->set_detachedLifespan (0);
+ mgmtObject->clr_expireTime();
+ agent->addObject (mgmtObject);
+ }
+ }
+ attach(h);
+}
+
+SessionState::~SessionState() {
+ if (mgmtObject != 0)
+ mgmtObject->resourceDestroy ();
+}
+
+AMQP_ClientProxy& SessionState::getProxy() {
+ assert(isAttached());
+ return handler->getProxy();
+}
+
+ConnectionState& SessionState::getConnection() {
+ assert(isAttached());
+ return handler->getConnection();
+}
+
+bool SessionState::isLocal(const ConnectionToken* t) const
+{
+ return isAttached() && &(handler->getConnection()) == t;
+}
+
+void SessionState::detach() {
+ QPID_LOG(debug, getId() << ": detached on broker.");
+ disableOutput();
+ handler = 0;
+ if (mgmtObject != 0)
+ mgmtObject->set_attached (0);
+}
+
+void SessionState::disableOutput()
+{
+ semanticState.detached();//prevents further activateOutput calls until reattached
+ getConnection().outputTasks.removeOutputTask(&semanticState);
+}
+
+void SessionState::attach(SessionHandler& h) {
+ QPID_LOG(debug, getId() << ": attached on broker.");
+ handler = &h;
+ if (mgmtObject != 0)
+ {
+ mgmtObject->set_attached (1);
+ mgmtObject->set_connectionRef (h.getConnection().GetManagementObject()->getObjectId());
+ mgmtObject->set_channelId (h.getChannel());
+ }
+}
+
+void SessionState::activateOutput() {
+ if (isAttached())
+ getConnection().outputTasks.activateOutput();
+}
+
+void SessionState::giveReadCredit(int32_t credit) {
+ if (isAttached())
+ getConnection().outputTasks.giveReadCredit(credit);
+}
+
+ManagementObject* SessionState::GetManagementObject (void) const
+{
+ return (ManagementObject*) mgmtObject;
+}
+
+Manageable::status_t SessionState::ManagementMethod (uint32_t methodId,
+ Args& /*args*/,
+ string& /*text*/)
+{
+ Manageable::status_t status = Manageable::STATUS_UNKNOWN_METHOD;
+
+ switch (methodId)
+ {
+ case _qmf::Session::METHOD_DETACH :
+ if (handler != 0) {
+ handler->sendDetach();
+ }
+ status = Manageable::STATUS_OK;
+ break;
+
+ case _qmf::Session::METHOD_CLOSE :
+ /*
+ if (handler != 0)
+ {
+ handler->getConnection().closeChannel(handler->getChannel());
+ }
+ status = Manageable::STATUS_OK;
+ break;
+ */
+
+ case _qmf::Session::METHOD_SOLICITACK :
+ case _qmf::Session::METHOD_RESETLIFESPAN :
+ status = Manageable::STATUS_NOT_IMPLEMENTED;
+ break;
+ }
+
+ return status;
+}
+
+void SessionState::handleCommand(framing::AMQMethodBody* method, const SequenceNumber& id) {
+ Invoker::Result invocation = invoke(adapter, *method);
+ receiverCompleted(id);
+ if (!invocation.wasHandled()) {
+ throw NotImplementedException(QPID_MSG("Not implemented: " << *method));
+ } else if (invocation.hasResult()) {
+ getProxy().getExecution().result(id, invocation.getResult());
+ }
+ if (method->isSync()) {
+ incomplete.process(enqueuedOp, true);
+ sendCompletion();
+ }
+}
+
+void SessionState::handleContent(AMQFrame& frame, const SequenceNumber& id)
+{
+ if (frame.getBof() && frame.getBos()) //start of frameset
+ msgBuilder.start(id);
+ intrusive_ptr<Message> msg(msgBuilder.getMessage());
+ msgBuilder.handle(frame);
+ if (frame.getEof() && frame.getEos()) {//end of frameset
+ if (frame.getBof()) {
+ //i.e this is a just a command frame, add a dummy header
+ AMQFrame header;
+ header.setBody(AMQHeaderBody());
+ header.setBof(false);
+ header.setEof(false);
+ msg->getFrames().append(header);
+ }
+ msg->setPublisher(&getConnection());
+ semanticState.handle(msg);
+ msgBuilder.end();
+
+ if (msg->isEnqueueComplete()) {
+ enqueued(msg);
+ } else {
+ incomplete.add(msg);
+ }
+
+ //hold up execution until async enqueue is complete
+ if (msg->getFrames().getMethod()->isSync()) {
+ incomplete.process(enqueuedOp, true);
+ sendCompletion();
+ } else {
+ incomplete.process(enqueuedOp, false);
+ }
+ }
+}
+
+void SessionState::enqueued(boost::intrusive_ptr<Message> msg)
+{
+ receiverCompleted(msg->getCommandId());
+ if (msg->requiresAccept())
+ getProxy().getMessage().accept(SequenceSet(msg->getCommandId()));
+}
+
+void SessionState::handleIn(AMQFrame& frame) {
+ SequenceNumber commandId = receiverGetCurrent();
+ //TODO: make command handling more uniform, regardless of whether
+ //commands carry content.
+ AMQMethodBody* m = frame.getMethod();
+ if (m == 0 || m->isContentBearing()) {
+ handleContent(frame, commandId);
+ } else if (frame.getBof() && frame.getEof()) {
+ handleCommand(frame.getMethod(), commandId);
+ } else {
+ throw InternalErrorException("Cannot handle multi-frame command segments yet");
+ }
+}
+
+void SessionState::handleOut(AMQFrame& frame) {
+ assert(handler);
+ handler->out(frame);
+}
+
+void SessionState::deliver(DeliveryRecord& msg)
+{
+ uint32_t maxFrameSize = getConnection().getFrameMax();
+ assert(senderGetCommandPoint().offset == 0);
+ SequenceNumber commandId = senderGetCommandPoint().command;
+ msg.deliver(getProxy().getHandler(), commandId, maxFrameSize);
+ assert(senderGetCommandPoint() == SessionPoint(commandId+1, 0)); // Delivery has moved sendPoint.
+}
+
+void SessionState::sendCompletion() { handler->sendCompletion(); }
+
+void SessionState::senderCompleted(const SequenceSet& commands) {
+ qpid::SessionState::senderCompleted(commands);
+ for (SequenceSet::RangeIterator i = commands.rangesBegin(); i != commands.rangesEnd(); i++)
+ semanticState.completed(i->first(), i->last());
+}
+
+void SessionState::readyToSend() {
+ QPID_LOG(debug, getId() << ": ready to send, activating output.");
+ assert(handler);
+ semanticState.attached();
+ sys::AggregateOutput& tasks = handler->getConnection().outputTasks;
+ tasks.addOutputTask(&semanticState);
+ tasks.activateOutput();
+}
+
+Broker& SessionState::getBroker() { return broker; }
+
+}} // namespace qpid::broker
diff --git a/RC9/qpid/cpp/src/qpid/broker/SessionState.h b/RC9/qpid/cpp/src/qpid/broker/SessionState.h
new file mode 100644
index 0000000000..035a444127
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/SessionState.h
@@ -0,0 +1,144 @@
+#ifndef QPID_BROKER_SESSION_H
+#define QPID_BROKER_SESSION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/SessionState.h"
+#include "qpid/framing/FrameHandler.h"
+#include "qpid/framing/SequenceSet.h"
+#include "qpid/sys/Time.h"
+#include "qpid/management/Manageable.h"
+#include "qmf/org/apache/qpid/broker/Session.h"
+#include "SessionAdapter.h"
+#include "DeliveryAdapter.h"
+#include "IncompleteMessageList.h"
+#include "MessageBuilder.h"
+#include "SessionContext.h"
+#include "SemanticState.h"
+
+#include <boost/noncopyable.hpp>
+#include <boost/scoped_ptr.hpp>
+
+#include <set>
+#include <vector>
+#include <ostream>
+
+namespace qpid {
+
+namespace framing {
+class AMQP_ClientProxy;
+}
+
+namespace broker {
+
+class Broker;
+class ConnectionState;
+class Message;
+class SessionHandler;
+class SessionManager;
+
+/**
+ * Broker-side session state includes session's handler chains, which
+ * may themselves have state.
+ */
+class SessionState : public qpid::SessionState,
+ public SessionContext,
+ public DeliveryAdapter,
+ public management::Manageable,
+ public framing::FrameHandler::InOutHandler
+{
+ public:
+ SessionState(Broker&, SessionHandler&, const SessionId&, const SessionState::Configuration&);
+ ~SessionState();
+ bool isAttached() const { return handler; }
+
+ void detach();
+ void attach(SessionHandler& handler);
+ void disableOutput();
+
+ /** @pre isAttached() */
+ framing::AMQP_ClientProxy& getProxy();
+
+ /** @pre isAttached() */
+ ConnectionState& getConnection();
+ bool isLocal(const ConnectionToken* t) const;
+
+ Broker& getBroker();
+
+ /** OutputControl **/
+ void activateOutput();
+ void giveReadCredit(int32_t);
+
+ void senderCompleted(const framing::SequenceSet& ranges);
+
+ void sendCompletion();
+
+ //delivery adapter methods:
+ void deliver(DeliveryRecord&);
+
+ // Manageable entry points
+ management::ManagementObject* GetManagementObject (void) const;
+ management::Manageable::status_t
+ ManagementMethod (uint32_t methodId, management::Args& args, std::string&);
+
+ void readyToSend();
+
+ // Used by cluster to create replica sessions.
+ SemanticState& getSemanticState() { return semanticState; }
+ boost::intrusive_ptr<Message> getMessageInProgress() { return msgBuilder.getMessage(); }
+
+ private:
+
+ void handleCommand(framing::AMQMethodBody* method, const framing::SequenceNumber& id);
+ void handleContent(framing::AMQFrame& frame, const framing::SequenceNumber& id);
+ void enqueued(boost::intrusive_ptr<Message> msg);
+
+ void handleIn(framing::AMQFrame& frame);
+ void handleOut(framing::AMQFrame& frame);
+
+ // End of the input & output chains.
+ void handleInLast(framing::AMQFrame& frame);
+ void handleOutLast(framing::AMQFrame& frame);
+
+ Broker& broker;
+ SessionHandler* handler;
+ sys::AbsTime expiry; // Used by SessionManager.
+ SemanticState semanticState;
+ SessionAdapter adapter;
+ MessageBuilder msgBuilder;
+ IncompleteMessageList incomplete;
+ IncompleteMessageList::CompletionListener enqueuedOp;
+ qmf::org::apache::qpid::broker::Session* mgmtObject;
+
+ friend class SessionManager;
+};
+
+
+inline std::ostream& operator<<(std::ostream& out, const SessionState& session) {
+ return out << session.getId();
+}
+
+}} // namespace qpid::broker
+
+
+
+#endif /*!QPID_BROKER_SESSION_H*/
diff --git a/RC9/qpid/cpp/src/qpid/broker/SignalHandler.cpp b/RC9/qpid/cpp/src/qpid/broker/SignalHandler.cpp
new file mode 100644
index 0000000000..7207b0f8ce
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/SignalHandler.cpp
@@ -0,0 +1,48 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "SignalHandler.h"
+#include "Broker.h"
+#include <signal.h>
+
+namespace qpid {
+namespace broker {
+
+boost::intrusive_ptr<Broker> SignalHandler::broker;
+
+void SignalHandler::setBroker(const boost::intrusive_ptr<Broker>& b) {
+ broker = b;
+
+ signal(SIGINT,shutdownHandler);
+ signal(SIGTERM, shutdownHandler);
+
+ signal(SIGHUP,SIG_IGN); // TODO aconway 2007-07-18: reload config.
+
+ signal(SIGCHLD,SIG_IGN);
+}
+
+void SignalHandler::shutdownHandler(int) {
+ if (broker.get()) {
+ broker->shutdown();
+ broker = 0; // Release the broker reference.
+ }
+}
+
+}} // namespace qpid::broker
diff --git a/RC9/qpid/cpp/src/qpid/broker/SignalHandler.h b/RC9/qpid/cpp/src/qpid/broker/SignalHandler.h
new file mode 100644
index 0000000000..d2cdfae07c
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/SignalHandler.h
@@ -0,0 +1,47 @@
+#ifndef QPID_BROKER_SIGNALHANDLER_H
+#define QPID_BROKER_SIGNALHANDLER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <boost/intrusive_ptr.hpp>
+
+namespace qpid {
+namespace broker {
+
+class Broker;
+
+/**
+ * Handle signals e.g. to shut-down a broker.
+ */
+class SignalHandler
+{
+ public:
+ /** Set the broker to be shutdown on signals */
+ static void setBroker(const boost::intrusive_ptr<Broker>& broker);
+
+ private:
+ static void shutdownHandler(int);
+ static boost::intrusive_ptr<Broker> broker;
+};
+}} // namespace qpid::broker
+
+#endif /*!QPID_BROKER_SIGNALHANDLER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/broker/System.cpp b/RC9/qpid/cpp/src/qpid/broker/System.cpp
new file mode 100644
index 0000000000..a11ad25bbe
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/System.cpp
@@ -0,0 +1,82 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+#include "System.h"
+#include "qpid/agent/ManagementAgent.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/sys/SystemInfo.h"
+#include <iostream>
+#include <fstream>
+
+using qpid::management::ManagementAgent;
+using namespace qpid::broker;
+using namespace std;
+namespace _qmf = qmf::org::apache::qpid::broker;
+
+System::System (string _dataDir) : mgmtObject(0)
+{
+ ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+
+ if (agent != 0)
+ {
+ framing::Uuid systemId;
+
+ if (_dataDir.empty ())
+ {
+ systemId.generate ();
+ }
+ else
+ {
+ string filename (_dataDir + "/systemId");
+ ifstream inFile (filename.c_str ());
+
+ if (inFile.good ())
+ {
+ inFile >> systemId;
+ inFile.close ();
+ }
+ else
+ {
+ systemId.generate ();
+ ofstream outFile (filename.c_str ());
+ if (outFile.good ())
+ {
+ outFile << systemId << endl;
+ outFile.close ();
+ }
+ }
+ }
+
+ mgmtObject = new _qmf::System (agent, this, systemId);
+ std::string sysname, nodename, release, version, machine;
+ qpid::sys::SystemInfo::getSystemId (sysname,
+ nodename,
+ release,
+ version,
+ machine);
+ mgmtObject->set_osName (sysname);
+ mgmtObject->set_nodeName (nodename);
+ mgmtObject->set_release (release);
+ mgmtObject->set_version (version);
+ mgmtObject->set_machine (machine);
+
+ agent->addObject (mgmtObject, 0x1000000000000001LL);
+ }
+}
+
diff --git a/RC9/qpid/cpp/src/qpid/broker/System.h b/RC9/qpid/cpp/src/qpid/broker/System.h
new file mode 100644
index 0000000000..42a816e095
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/System.h
@@ -0,0 +1,49 @@
+#ifndef _BrokerSystem_
+#define _BrokerSystem_
+
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+#include "qpid/management/Manageable.h"
+#include "qmf/org/apache/qpid/broker/System.h"
+#include <boost/shared_ptr.hpp>
+#include <string>
+
+namespace qpid {
+namespace broker {
+
+class System : public management::Manageable
+{
+ private:
+
+ qmf::org::apache::qpid::broker::System* mgmtObject;
+
+ public:
+
+ typedef boost::shared_ptr<System> shared_ptr;
+
+ System (std::string _dataDir);
+
+ management::ManagementObject* GetManagementObject (void) const
+ { return mgmtObject; }
+};
+
+}}
+
+#endif /*!_BrokerSystem_*/
diff --git a/RC9/qpid/cpp/src/qpid/broker/Timer.cpp b/RC9/qpid/cpp/src/qpid/broker/Timer.cpp
new file mode 100644
index 0000000000..0b0d3ba63d
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/Timer.cpp
@@ -0,0 +1,104 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "Timer.h"
+#include <iostream>
+
+using boost::intrusive_ptr;
+using qpid::sys::AbsTime;
+using qpid::sys::Duration;
+using qpid::sys::Monitor;
+using qpid::sys::Thread;
+using namespace qpid::broker;
+
+TimerTask::TimerTask(Duration timeout) :
+ duration(timeout), time(AbsTime::now(), timeout), cancelled(false) {}
+
+TimerTask::TimerTask(AbsTime _time) :
+ duration(0), time(_time), cancelled(false) {}
+
+TimerTask::~TimerTask(){}
+
+void TimerTask::reset() { time = AbsTime(AbsTime::now(), duration); }
+
+Timer::Timer() : active(false)
+{
+ start();
+}
+
+Timer::~Timer()
+{
+ stop();
+}
+
+void Timer::run()
+{
+ Monitor::ScopedLock l(monitor);
+ while(active){
+ if (tasks.empty()) {
+ monitor.wait();
+ } else {
+ intrusive_ptr<TimerTask> t = tasks.top();
+ if (t->cancelled) {
+ tasks.pop();
+ } else if(t->time < AbsTime::now()) {
+ tasks.pop();
+ Monitor::ScopedUnlock u(monitor);
+ t->fire();
+ } else {
+ monitor.wait(t->time);
+ }
+ }
+ }
+}
+
+void Timer::add(intrusive_ptr<TimerTask> task)
+{
+ Monitor::ScopedLock l(monitor);
+ tasks.push(task);
+ monitor.notify();
+}
+
+void Timer::start()
+{
+ Monitor::ScopedLock l(monitor);
+ if (!active) {
+ active = true;
+ runner = Thread(this);
+ }
+}
+
+void Timer::stop()
+{
+ {
+ Monitor::ScopedLock l(monitor);
+ if (!active) return;
+ active = false;
+ monitor.notifyAll();
+ }
+ runner.join();
+}
+
+bool Later::operator()(const intrusive_ptr<TimerTask>& a,
+ const intrusive_ptr<TimerTask>& b) const
+{
+ return a.get() && b.get() && a->time > b->time;
+}
+
diff --git a/RC9/qpid/cpp/src/qpid/broker/Timer.h b/RC9/qpid/cpp/src/qpid/broker/Timer.h
new file mode 100644
index 0000000000..f702f0f32d
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/Timer.h
@@ -0,0 +1,79 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _Timer_
+#define _Timer_
+
+#include "qpid/sys/Monitor.h"
+#include "qpid/sys/Thread.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/RefCounted.h"
+
+#include <memory>
+#include <queue>
+
+#include <boost/intrusive_ptr.hpp>
+
+namespace qpid {
+namespace broker {
+
+struct TimerTask : public RefCounted {
+ const qpid::sys::Duration duration;
+ qpid::sys::AbsTime time;
+ volatile bool cancelled;
+
+ TimerTask(qpid::sys::Duration timeout);
+ TimerTask(qpid::sys::AbsTime time);
+ virtual ~TimerTask();
+ void reset();
+ virtual void fire() = 0;
+};
+
+struct Later {
+ bool operator()(const boost::intrusive_ptr<TimerTask>& a,
+ const boost::intrusive_ptr<TimerTask>& b) const;
+};
+
+class Timer : private qpid::sys::Runnable {
+ protected:
+ qpid::sys::Monitor monitor;
+ std::priority_queue<boost::intrusive_ptr<TimerTask>,
+ std::vector<boost::intrusive_ptr<TimerTask> >,
+ Later> tasks;
+ qpid::sys::Thread runner;
+ bool active;
+
+ virtual void run();
+
+ public:
+ Timer();
+ virtual ~Timer();
+
+ void add(boost::intrusive_ptr<TimerTask> task);
+ void start();
+ void stop();
+
+};
+
+
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/TopicExchange.cpp b/RC9/qpid/cpp/src/qpid/broker/TopicExchange.cpp
new file mode 100644
index 0000000000..d4f9721162
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/TopicExchange.cpp
@@ -0,0 +1,313 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "TopicExchange.h"
+#include <algorithm>
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::sys;
+namespace _qmf = qmf::org::apache::qpid::broker;
+
+// TODO aconway 2006-09-20: More efficient matching algorithm.
+// Areas for improvement:
+// - excessive string copying: should be 0 copy, match from original buffer.
+// - match/lookup: use descision tree or other more efficient structure.
+
+namespace
+{
+const std::string qpidFedOp("qpid.fed.op");
+const std::string qpidFedTags("qpid.fed.tags");
+const std::string qpidFedOrigin("qpid.fed.origin");
+
+const std::string fedOpBind("B");
+const std::string fedOpUnbind("U");
+const std::string fedOpReorigin("R");
+const std::string fedOpHello("H");
+}
+
+Tokens& Tokens::operator=(const std::string& s) {
+ clear();
+ if (s.empty()) return *this;
+ std::string::const_iterator i = s.begin();
+ while (true) {
+ // Invariant: i is at the beginning of the next untokenized word.
+ std::string::const_iterator j = std::find(i, s.end(), '.');
+ push_back(std::string(i, j));
+ if (j == s.end()) return *this;
+ i = j + 1;
+ }
+ return *this;
+}
+
+TopicPattern& TopicPattern::operator=(const Tokens& tokens) {
+ Tokens::operator=(tokens);
+ normalize();
+ return *this;
+}
+
+void Tokens::key(string& keytext) const
+{
+ for (std::vector<string>::const_iterator iter = begin(); iter != end(); iter++) {
+ if (iter != begin())
+ keytext += ".";
+ keytext += *iter;
+ }
+}
+
+namespace {
+const std::string hashmark("#");
+const std::string star("*");
+}
+
+void TopicPattern::normalize() {
+ std::string word;
+ Tokens::iterator i = begin();
+ while (i != end()) {
+ if (*i == hashmark) {
+ ++i;
+ while (i != end()) {
+ // Invariant: *(i-1)==#, [begin()..i-1] is normalized.
+ if (*i == star) { // Move * before #.
+ std::swap(*i, *(i-1));
+ ++i;
+ } else if (*i == hashmark) {
+ erase(i); // Remove extra #
+ } else {
+ break;
+ }
+ }
+ } else {
+ i ++;
+ }
+ }
+}
+
+
+namespace {
+// TODO aconway 2006-09-20: Inefficient to convert every routingKey to a string.
+// Need StringRef class that operates on a string in place witout copy.
+// Should be applied everywhere strings are extracted from frames.
+//
+bool do_match(Tokens::const_iterator pattern_begin, Tokens::const_iterator pattern_end, Tokens::const_iterator target_begin, Tokens::const_iterator target_end)
+{
+ // Invariant: [pattern_begin..p) matches [target_begin..t)
+ Tokens::const_iterator p = pattern_begin;
+ Tokens::const_iterator t = target_begin;
+ while (p != pattern_end && t != target_end)
+ {
+ if (*p == star || *p == *t) {
+ ++p, ++t;
+ } else if (*p == hashmark) {
+ ++p;
+ if (do_match(p, pattern_end, t, target_end)) return true;
+ while (t != target_end) {
+ ++t;
+ if (do_match(p, pattern_end, t, target_end)) return true;
+ }
+ return false;
+ } else {
+ return false;
+ }
+ }
+ while (p != pattern_end && *p == hashmark) ++p; // Ignore trailing #
+ return t == target_end && p == pattern_end;
+}
+}
+
+bool TopicPattern::match(const Tokens& target) const
+{
+ return do_match(begin(), end(), target.begin(), target.end());
+}
+
+TopicExchange::TopicExchange(const string& _name, Manageable* _parent) : Exchange(_name, _parent)
+{
+ if (mgmtExchange != 0)
+ mgmtExchange->set_type (typeName);
+}
+
+TopicExchange::TopicExchange(const std::string& _name, bool _durable,
+ const FieldTable& _args, Manageable* _parent) :
+ Exchange(_name, _durable, _args, _parent)
+{
+ if (mgmtExchange != 0)
+ mgmtExchange->set_type (typeName);
+}
+
+bool TopicExchange::bind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* args)
+{
+ string fedOp(args ? args->getAsString(qpidFedOp) : fedOpBind);
+ string fedTags(args ? args->getAsString(qpidFedTags) : "");
+ string fedOrigin(args ? args->getAsString(qpidFedOrigin) : "");
+ bool propagate = false;
+ bool reallyUnbind;
+ TopicPattern routingPattern(routingKey);
+
+ if (args == 0 || fedOp.empty() || fedOp == fedOpBind) {
+ RWlock::ScopedWlock l(lock);
+ if (isBound(queue, routingPattern)) {
+ return false;
+ } else {
+ Binding::shared_ptr binding (new Binding (routingKey, queue, this, FieldTable(), fedOrigin));
+ BoundKey& bk = bindings[routingPattern];
+ bk.bindingVector.push_back(binding);
+ propagate = bk.fedBinding.addOrigin(fedOrigin);
+ if (mgmtExchange != 0) {
+ mgmtExchange->inc_bindingCount();
+ ((_qmf::Queue*) queue->GetManagementObject())->inc_bindingCount();
+ }
+ }
+ } else if (fedOp == fedOpUnbind) {
+ {
+ RWlock::ScopedWlock l(lock);
+ BoundKey& bk = bindings[routingPattern];
+ propagate = bk.fedBinding.delOrigin(fedOrigin);
+ reallyUnbind = bk.fedBinding.count() == 0;
+ }
+ if (reallyUnbind)
+ unbind(queue, routingKey, 0);
+ } else if (fedOp == fedOpReorigin) {
+ for (std::map<TopicPattern, BoundKey>::iterator iter = bindings.begin();
+ iter != bindings.end(); iter++) {
+ const BoundKey& bk = iter->second;
+ if (bk.fedBinding.hasLocal()) {
+ string propKey;
+ iter->first.key(propKey);
+ propagateFedOp(propKey, string(), fedOpBind, string());
+ }
+ }
+ }
+
+ routeIVE();
+ if (propagate)
+ propagateFedOp(routingKey, fedTags, fedOp, fedOrigin);
+ return true;
+}
+
+bool TopicExchange::unbind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* /*args*/){
+ RWlock::ScopedWlock l(lock);
+ BindingMap::iterator bi = bindings.find(TopicPattern(routingKey));
+ if (bi == bindings.end()) return false;
+ BoundKey& bk = bi->second;
+ Binding::vector& qv(bk.bindingVector);
+ bool propagate = false;
+
+ Binding::vector::iterator q;
+ for (q = qv.begin(); q != qv.end(); q++)
+ if ((*q)->queue == queue)
+ break;
+ if(q == qv.end()) return false;
+ qv.erase(q);
+ propagate = bk.fedBinding.delOrigin();
+ if(qv.empty()) bindings.erase(bi);
+ if (mgmtExchange != 0) {
+ mgmtExchange->dec_bindingCount();
+ ((_qmf::Queue*) queue->GetManagementObject())->dec_bindingCount();
+ }
+
+ if (propagate)
+ propagateFedOp(routingKey, string(), fedOpUnbind, string());
+ return true;
+}
+
+bool TopicExchange::isBound(Queue::shared_ptr queue, TopicPattern& pattern)
+{
+ BindingMap::iterator bi = bindings.find(pattern);
+ if (bi == bindings.end()) return false;
+ Binding::vector& qv(bi->second.bindingVector);
+ Binding::vector::iterator q;
+ for (q = qv.begin(); q != qv.end(); q++)
+ if ((*q)->queue == queue)
+ break;
+ return q != qv.end();
+}
+
+void TopicExchange::route(Deliverable& msg, const string& routingKey, const FieldTable* /*args*/){
+ Binding::vector mb;
+ PreRoute pr(msg, this);
+ uint32_t count(0);
+
+ {
+ RWlock::ScopedRlock l(lock);
+ Tokens tokens(routingKey);
+
+ for (BindingMap::iterator i = bindings.begin(); i != bindings.end(); ++i) {
+ if (i->first.match(tokens)) {
+ Binding::vector& qv(i->second.bindingVector);
+ for(Binding::vector::iterator j = qv.begin(); j != qv.end(); j++, count++){
+ mb.push_back(*j);
+ }
+ }
+ }
+ }
+
+ for (Binding::vector::iterator j = mb.begin(); j != mb.end(); ++j) {
+ msg.deliverTo((*j)->queue);
+ if ((*j)->mgmtBinding != 0)
+ (*j)->mgmtBinding->inc_msgMatched ();
+ }
+
+ if (mgmtExchange != 0)
+ {
+ mgmtExchange->inc_msgReceives ();
+ mgmtExchange->inc_byteReceives (msg.contentSize ());
+ if (count == 0)
+ {
+ mgmtExchange->inc_msgDrops ();
+ mgmtExchange->inc_byteDrops (msg.contentSize ());
+ }
+ else
+ {
+ mgmtExchange->inc_msgRoutes (count);
+ mgmtExchange->inc_byteRoutes (count * msg.contentSize ());
+ }
+ }
+}
+
+bool TopicExchange::isBound(Queue::shared_ptr queue, const string* const routingKey, const FieldTable* const)
+{
+ if (routingKey && queue) {
+ TopicPattern key(*routingKey);
+ return isBound(queue, key);
+ } else if (!routingKey && !queue) {
+ return bindings.size() > 0;
+ } else if (routingKey) {
+ for (BindingMap::iterator i = bindings.begin(); i != bindings.end(); ++i) {
+ if (i->first.match(*routingKey)) {
+ return true;
+ }
+ }
+ } else {
+ for (BindingMap::iterator i = bindings.begin(); i != bindings.end(); ++i) {
+ Binding::vector& qv(i->second.bindingVector);
+ Binding::vector::iterator q;
+ for (q = qv.begin(); q != qv.end(); q++)
+ if ((*q)->queue == queue)
+ return true;
+ }
+ }
+ return false;
+}
+
+TopicExchange::~TopicExchange() {}
+
+const std::string TopicExchange::typeName("topic");
+
+
diff --git a/RC9/qpid/cpp/src/qpid/broker/TopicExchange.h b/RC9/qpid/cpp/src/qpid/broker/TopicExchange.h
new file mode 100644
index 0000000000..f3a2e221f7
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/TopicExchange.h
@@ -0,0 +1,110 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _TopicExchange_
+#define _TopicExchange_
+
+#include <map>
+#include <vector>
+#include "Exchange.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/sys/Monitor.h"
+#include "Queue.h"
+
+namespace qpid {
+namespace broker {
+
+/** A vector of string tokens */
+class Tokens : public std::vector<std::string> {
+ public:
+ Tokens() {};
+ // Default copy, assign, dtor are sufficient.
+
+ /** Tokenize s, provides automatic conversion of string to Tokens */
+ Tokens(const std::string& s) { operator=(s); }
+ /** Tokenizing assignment operator s */
+ Tokens & operator=(const std::string& s);
+ void key(std::string& key) const;
+
+ private:
+ size_t hash;
+};
+
+
+/**
+ * Tokens that have been normalized as a pattern and can be matched
+ * with topic Tokens. Normalized meands all sequences of mixed * and
+ * # are reduced to a series of * followed by at most one #.
+ */
+class TopicPattern : public Tokens
+{
+ public:
+ TopicPattern() {}
+ // Default copy, assign, dtor are sufficient.
+ TopicPattern(const Tokens& tokens) { operator=(tokens); }
+ TopicPattern(const std::string& str) { operator=(str); }
+ TopicPattern& operator=(const Tokens&);
+ TopicPattern& operator=(const std::string& str) { return operator=(Tokens(str)); }
+
+ /** Match a topic */
+ bool match(const std::string& topic) { return match(Tokens(topic)); }
+ bool match(const Tokens& topic) const;
+
+ private:
+ void normalize();
+};
+
+class TopicExchange : public virtual Exchange {
+ struct BoundKey {
+ Binding::vector bindingVector;
+ FedBinding fedBinding;
+ };
+ typedef std::map<TopicPattern, BoundKey> BindingMap;
+ BindingMap bindings;
+ qpid::sys::RWlock lock;
+
+ bool isBound(Queue::shared_ptr queue, TopicPattern& pattern);
+ public:
+ static const std::string typeName;
+
+ TopicExchange(const string& name, management::Manageable* parent = 0);
+ TopicExchange(const string& _name, bool _durable,
+ const qpid::framing::FieldTable& _args, management::Manageable* parent = 0);
+
+ virtual std::string getType() const { return typeName; }
+
+ virtual bool bind(Queue::shared_ptr queue, const string& routingKey, const qpid::framing::FieldTable* args);
+
+ virtual bool unbind(Queue::shared_ptr queue, const string& routingKey, const qpid::framing::FieldTable* args);
+
+ virtual void route(Deliverable& msg, const string& routingKey, const qpid::framing::FieldTable* args);
+
+ virtual bool isBound(Queue::shared_ptr queue, const string* const routingKey, const qpid::framing::FieldTable* const args);
+
+ virtual ~TopicExchange();
+ virtual bool supportsDynamicBinding() { return true; }
+};
+
+
+
+}
+}
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/TransactionalStore.h b/RC9/qpid/cpp/src/qpid/broker/TransactionalStore.h
new file mode 100644
index 0000000000..2a2bac0c51
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/TransactionalStore.h
@@ -0,0 +1,60 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _TransactionalStore_
+#define _TransactionalStore_
+
+#include <memory>
+#include <string>
+#include <set>
+
+namespace qpid {
+namespace broker {
+
+struct InvalidTransactionContextException : public std::exception {};
+
+class TransactionContext {
+public:
+ virtual ~TransactionContext(){}
+};
+
+class TPCTransactionContext : public TransactionContext {
+public:
+ virtual ~TPCTransactionContext(){}
+};
+
+class TransactionalStore {
+public:
+ virtual std::auto_ptr<TransactionContext> begin() = 0;
+ virtual std::auto_ptr<TPCTransactionContext> begin(const std::string& xid) = 0;
+ virtual void prepare(TPCTransactionContext& txn) = 0;
+ virtual void commit(TransactionContext& txn) = 0;
+ virtual void abort(TransactionContext& txn) = 0;
+
+ virtual void collectPreparedXids(std::set<std::string>& xids) = 0;
+
+ virtual ~TransactionalStore(){}
+};
+
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/TxAccept.cpp b/RC9/qpid/cpp/src/qpid/broker/TxAccept.cpp
new file mode 100644
index 0000000000..c7001e5526
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/TxAccept.cpp
@@ -0,0 +1,99 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "TxAccept.h"
+#include "qpid/log/Statement.h"
+
+using std::bind1st;
+using std::bind2nd;
+using std::mem_fun_ref;
+using namespace qpid::broker;
+using qpid::framing::SequenceSet;
+using qpid::framing::SequenceNumber;
+
+TxAccept::RangeOp::RangeOp(const AckRange& r) : range(r) {}
+
+void TxAccept::RangeOp::prepare(TransactionContext* ctxt)
+{
+ for_each(range.start, range.end, bind(&DeliveryRecord::dequeue, _1, ctxt));
+}
+
+void TxAccept::RangeOp::commit()
+{
+ for_each(range.start, range.end, bind(&DeliveryRecord::committed, _1));
+ for_each(range.start, range.end, bind(&DeliveryRecord::setEnded, _1));
+}
+
+TxAccept::RangeOps::RangeOps(DeliveryRecords& u) : unacked(u) {}
+
+void TxAccept::RangeOps::operator()(SequenceNumber start, SequenceNumber end)
+{
+ ranges.push_back(RangeOp(DeliveryRecord::findRange(unacked, start, end)));
+}
+
+void TxAccept::RangeOps::prepare(TransactionContext* ctxt)
+{
+ for_each(ranges.begin(), ranges.end(), bind(&RangeOp::prepare, _1, ctxt));
+}
+
+void TxAccept::RangeOps::commit()
+{
+ for_each(ranges.begin(), ranges.end(), bind(&RangeOp::commit, _1));
+ //now remove if isRedundant():
+ if (!ranges.empty()) {
+ ack_iterator i = ranges.front().range.start;
+ ack_iterator end = ranges.back().range.end;
+ while (i != end) {
+ if (i->isRedundant()) {
+ i = unacked.erase(i);
+ } else {
+ i++;
+ }
+ }
+ }
+}
+
+TxAccept::TxAccept(const SequenceSet& _acked, DeliveryRecords& _unacked) :
+ acked(_acked), unacked(_unacked), ops(unacked)
+{
+ //populate the ops
+ acked.for_each(ops);
+}
+
+bool TxAccept::prepare(TransactionContext* ctxt) throw()
+{
+ try{
+ ops.prepare(ctxt);
+ return true;
+ }catch(const std::exception& e){
+ QPID_LOG(error, "Failed to prepare: " << e.what());
+ return false;
+ }catch(...){
+ QPID_LOG(error, "Failed to prepare");
+ return false;
+ }
+}
+
+void TxAccept::commit() throw()
+{
+ ops.commit();
+}
+
+void TxAccept::rollback() throw() {}
diff --git a/RC9/qpid/cpp/src/qpid/broker/TxAccept.h b/RC9/qpid/cpp/src/qpid/broker/TxAccept.h
new file mode 100644
index 0000000000..0a5fdedb0a
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/TxAccept.h
@@ -0,0 +1,83 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _TxAccept_
+#define _TxAccept_
+
+#include <algorithm>
+#include <functional>
+#include <list>
+#include "qpid/framing/SequenceSet.h"
+#include "DeliveryRecord.h"
+#include "TxOp.h"
+
+namespace qpid {
+ namespace broker {
+ /**
+ * Defines the transactional behaviour for accepts received by
+ * a transactional channel.
+ */
+ class TxAccept : public TxOp {
+ struct RangeOp
+ {
+ AckRange range;
+
+ RangeOp(const AckRange& r);
+ void prepare(TransactionContext* ctxt);
+ void commit();
+ };
+
+ struct RangeOps
+ {
+ std::vector<RangeOp> ranges;
+ DeliveryRecords& unacked;
+
+ RangeOps(DeliveryRecords& u);
+
+ void operator()(framing::SequenceNumber start, framing::SequenceNumber end);
+ void prepare(TransactionContext* ctxt);
+ void commit();
+ };
+
+ framing::SequenceSet acked;
+ DeliveryRecords& unacked;
+ RangeOps ops;
+
+ public:
+ /**
+ * @param acked a representation of the accumulation of
+ * acks received
+ * @param unacked the record of delivered messages
+ */
+ TxAccept(const framing::SequenceSet& acked, DeliveryRecords& unacked);
+ virtual bool prepare(TransactionContext* ctxt) throw();
+ virtual void commit() throw();
+ virtual void rollback() throw();
+ virtual ~TxAccept(){}
+ virtual void accept(TxOpConstVisitor& visitor) const { visitor(*this); }
+
+ // Used by cluster replication.
+ const framing::SequenceSet& getAcked() const { return acked; }
+ };
+ }
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/TxBuffer.cpp b/RC9/qpid/cpp/src/qpid/broker/TxBuffer.cpp
new file mode 100644
index 0000000000..ae18e0f318
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/TxBuffer.cpp
@@ -0,0 +1,80 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "TxBuffer.h"
+#include "qpid/log/Statement.h"
+
+#include <boost/mem_fn.hpp>
+#include <boost/bind.hpp>
+using boost::mem_fn;
+using namespace qpid::broker;
+
+bool TxBuffer::prepare(TransactionContext* const ctxt)
+{
+ for(op_iterator i = ops.begin(); i < ops.end(); i++){
+ if(!(*i)->prepare(ctxt)){
+ return false;
+ }
+ }
+ return true;
+}
+
+void TxBuffer::commit()
+{
+ std::for_each(ops.begin(), ops.end(), mem_fn(&TxOp::commit));
+ ops.clear();
+}
+
+void TxBuffer::rollback()
+{
+ std::for_each(ops.begin(), ops.end(), mem_fn(&TxOp::rollback));
+ ops.clear();
+}
+
+void TxBuffer::enlist(TxOp::shared_ptr op)
+{
+ ops.push_back(op);
+}
+
+bool TxBuffer::commitLocal(TransactionalStore* const store)
+{
+ if (!store) return false;
+ try {
+ std::auto_ptr<TransactionContext> ctxt = store->begin();
+ if (prepare(ctxt.get())) {
+ store->commit(*ctxt);
+ commit();
+ return true;
+ } else {
+ store->abort(*ctxt);
+ rollback();
+ return false;
+ }
+ } catch (std::exception& e) {
+ QPID_LOG(error, "Commit failed with exception: " << e.what());
+ } catch (...) {
+ QPID_LOG(error, "Commit failed with unknown exception");
+ }
+ return false;
+}
+
+void TxBuffer::accept(TxOpConstVisitor& v) const {
+ std::for_each(ops.begin(), ops.end(), boost::bind(&TxOp::accept, _1, boost::ref(v)));
+}
diff --git a/RC9/qpid/cpp/src/qpid/broker/TxBuffer.h b/RC9/qpid/cpp/src/qpid/broker/TxBuffer.h
new file mode 100644
index 0000000000..aabb5ea0b1
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/TxBuffer.h
@@ -0,0 +1,118 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _TxBuffer_
+#define _TxBuffer_
+
+#include <algorithm>
+#include <functional>
+#include <vector>
+#include "TransactionalStore.h"
+#include "TxOp.h"
+
+/**
+ * Represents a single transaction. As such, an instance of this class
+ * will hold a list of operations representing the workload of the
+ * transaction. This work can be committed or rolled back. Committing
+ * is a two-stage process: first all the operations should be
+ * prepared, then if that succeeds they can be committed.
+ *
+ * In the 2pc case, a successful prepare may be followed by either a
+ * commit or a rollback.
+ *
+ * Atomicity of prepare is ensured by using a lower level
+ * transactional facility. This saves explicitly rolling back all the
+ * successfully prepared ops when one of them fails. i.e. we do not
+ * use 2pc internally, we instead ensure that prepare is atomic at a
+ * lower level. This makes individual prepare operations easier to
+ * code.
+ *
+ * Transactions on a messaging broker effect three types of 'action':
+ * (1) updates to persistent storage (2) updates to transient storage
+ * or cached data (3) network writes.
+ *
+ * Of these, (1) should always occur atomically during prepare to
+ * ensure that if the broker crashes while a transaction is being
+ * completed the persistent state (which is all that then remains) is
+ * consistent. (3) can only be done on commit, after a successful
+ * prepare. There is a little more flexibility with (2) but any
+ * changes made during prepare should be subject to the control of the
+ * TransactionalStore in use.
+ */
+namespace qpid {
+ namespace broker {
+ class TxBuffer{
+ typedef std::vector<TxOp::shared_ptr>::iterator op_iterator;
+ std::vector<TxOp::shared_ptr> ops;
+ protected:
+
+ public:
+ typedef boost::shared_ptr<TxBuffer> shared_ptr;
+ /**
+ * Adds an operation to the transaction.
+ */
+ void enlist(TxOp::shared_ptr op);
+
+ /**
+ * Requests that all ops are prepared. This should
+ * primarily involve making sure that a persistent record
+ * of the operations is stored where necessary.
+ *
+ * Once prepared, a transaction can be committed (or in
+ * the 2pc case, rolled back).
+ *
+ * @returns true if all the operations prepared
+ * successfully, false if not.
+ */
+ bool prepare(TransactionContext* const ctxt);
+
+ /**
+ * Signals that the ops all prepared successfully and can
+ * now commit, i.e. the operation can now be fully carried
+ * out.
+ *
+ * Should only be called after a call to prepare() returns
+ * true.
+ */
+ void commit();
+
+ /**
+ * Signals that all ops can be rolled back.
+ *
+ * Should only be called either after a call to prepare()
+ * returns true (2pc) or instead of a prepare call
+ * ('server-local')
+ */
+ void rollback();
+
+ /**
+ * Helper method for managing the process of server local
+ * commit
+ */
+ bool commitLocal(TransactionalStore* const store);
+
+ // Used by cluster to replicate transaction status.
+ void accept(TxOpConstVisitor& v) const;
+ };
+ }
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/TxOp.h b/RC9/qpid/cpp/src/qpid/broker/TxOp.h
new file mode 100644
index 0000000000..e0e17fc0dc
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/TxOp.h
@@ -0,0 +1,46 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _TxOp_
+#define _TxOp_
+
+#include "TxOpVisitor.h"
+#include "TransactionalStore.h"
+#include <boost/shared_ptr.hpp>
+
+namespace qpid {
+ namespace broker {
+
+ class TxOp{
+ public:
+ typedef boost::shared_ptr<TxOp> shared_ptr;
+
+ virtual bool prepare(TransactionContext*) throw() = 0;
+ virtual void commit() throw() = 0;
+ virtual void rollback() throw() = 0;
+ virtual ~TxOp(){}
+
+ virtual void accept(TxOpConstVisitor&) const = 0;
+ };
+
+}} // namespace qpid::broker
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/TxOpVisitor.h b/RC9/qpid/cpp/src/qpid/broker/TxOpVisitor.h
new file mode 100644
index 0000000000..a5f2a018c9
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/TxOpVisitor.h
@@ -0,0 +1,100 @@
+#ifndef QPID_BROKER_TXOPVISITOR_H
+#define QPID_BROKER_TXOPVISITOR_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/shared_ptr.h"
+
+namespace qpid {
+namespace broker {
+
+class DtxAck;
+class RecoveredDequeue;
+class RecoveredEnqueue;
+class TxAccept;
+class TxPublish;
+
+/**
+ * Visitor for TxOp familly of classes.
+ */
+struct TxOpConstVisitor
+{
+ virtual ~TxOpConstVisitor() {}
+ virtual void operator()(const DtxAck&) = 0;
+ virtual void operator()(const RecoveredDequeue&) = 0;
+ virtual void operator()(const RecoveredEnqueue&) = 0;
+ virtual void operator()(const TxAccept&) = 0;
+ virtual void operator()(const TxPublish&) = 0;
+};
+
+}} // namespace qpid::broker
+
+#endif /*!QPID_BROKER_TXOPVISITOR_H*/
+#ifndef QPID_BROKER_TXOPVISITOR_H
+#define QPID_BROKER_TXOPVISITOR_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/shared_ptr.h"
+
+namespace qpid {
+namespace broker {
+
+class DtxAck;
+class RecoveredDequeue;
+class RecoveredEnqueue;
+class TxAccept;
+class TxPublish;
+
+/**
+ * Visitor for TxOp familly of classes.
+ */
+struct TxOpConstVisitor
+{
+ virtual ~TxOpConstVisitor() {}
+ virtual void operator()(const DtxAck&) = 0;
+ virtual void operator()(const RecoveredDequeue&) = 0;
+ virtual void operator()(const RecoveredEnqueue&) = 0;
+ virtual void operator()(const TxAccept&) = 0;
+ virtual void operator()(const TxPublish&) = 0;
+};
+
+}} // namespace qpid::broker
+
+#endif /*!QPID_BROKER_TXOPVISITOR_H*/
diff --git a/RC9/qpid/cpp/src/qpid/broker/TxPublish.cpp b/RC9/qpid/cpp/src/qpid/broker/TxPublish.cpp
new file mode 100644
index 0000000000..25ac691ada
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/TxPublish.cpp
@@ -0,0 +1,80 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/log/Statement.h"
+#include "TxPublish.h"
+
+using boost::intrusive_ptr;
+using namespace qpid::broker;
+
+TxPublish::TxPublish(intrusive_ptr<Message> _msg) : msg(_msg) {}
+
+bool TxPublish::prepare(TransactionContext* ctxt) throw(){
+ try{
+ for_each(queues.begin(), queues.end(), Prepare(ctxt, msg));
+ return true;
+ }catch(const std::exception& e){
+ QPID_LOG(error, "Failed to prepare: " << e.what());
+ }catch(...){
+ QPID_LOG(error, "Failed to prepare (unknown error)");
+ }
+ return false;
+}
+
+void TxPublish::commit() throw(){
+ for_each(queues.begin(), queues.end(), Commit(msg));
+}
+
+void TxPublish::rollback() throw(){
+}
+
+void TxPublish::deliverTo(const boost::shared_ptr<Queue>& queue){
+ if (!queue->isLocal(msg)) {
+ queues.push_back(queue);
+ delivered = true;
+ } else {
+ QPID_LOG(debug, "Won't enqueue local message for " << queue->getName());
+ }
+}
+
+TxPublish::Prepare::Prepare(TransactionContext* _ctxt, intrusive_ptr<Message>& _msg)
+ : ctxt(_ctxt), msg(_msg){}
+
+void TxPublish::Prepare::operator()(const boost::shared_ptr<Queue>& queue){
+ if (!queue->enqueue(ctxt, msg)){
+ /**
+ * if not store then mark message for ack and deleivery once
+ * commit happens, as async IO will never set it when no store
+ * exists
+ */
+ msg->enqueueComplete();
+ }
+}
+
+TxPublish::Commit::Commit(intrusive_ptr<Message>& _msg) : msg(_msg){}
+
+void TxPublish::Commit::operator()(const boost::shared_ptr<Queue>& queue){
+ queue->process(msg);
+}
+
+uint64_t TxPublish::contentSize ()
+{
+ return msg->contentSize ();
+}
diff --git a/RC9/qpid/cpp/src/qpid/broker/TxPublish.h b/RC9/qpid/cpp/src/qpid/broker/TxPublish.h
new file mode 100644
index 0000000000..1f73cb8767
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/TxPublish.h
@@ -0,0 +1,89 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _TxPublish_
+#define _TxPublish_
+
+#include "Queue.h"
+#include "Deliverable.h"
+#include "Message.h"
+#include "MessageStore.h"
+#include "TxOp.h"
+
+#include <algorithm>
+#include <functional>
+#include <list>
+
+#include <boost/intrusive_ptr.hpp>
+
+namespace qpid {
+ namespace broker {
+ /**
+ * Defines the behaviour for publish operations on a
+ * transactional channel. Messages are routed through
+ * exchanges when received but are not at that stage delivered
+ * to the matching queues, rather the queues are held in an
+ * instance of this class. On prepare() the message is marked
+ * enqueued to the relevant queues in the MessagesStore. On
+ * commit() the messages will be passed to the queue for
+ * dispatch or to be added to the in-memory queue.
+ */
+ class TxPublish : public TxOp, public Deliverable{
+ class Prepare{
+ TransactionContext* ctxt;
+ boost::intrusive_ptr<Message>& msg;
+ public:
+ Prepare(TransactionContext* ctxt, boost::intrusive_ptr<Message>& msg);
+ void operator()(const boost::shared_ptr<Queue>& queue);
+ };
+
+ class Commit{
+ boost::intrusive_ptr<Message>& msg;
+ public:
+ Commit(boost::intrusive_ptr<Message>& msg);
+ void operator()(const boost::shared_ptr<Queue>& queue);
+ };
+
+ boost::intrusive_ptr<Message> msg;
+ std::list<Queue::shared_ptr> queues;
+
+ public:
+ TxPublish(boost::intrusive_ptr<Message> msg);
+ virtual bool prepare(TransactionContext* ctxt) throw();
+ virtual void commit() throw();
+ virtual void rollback() throw();
+
+ virtual Message& getMessage() { return *msg; };
+
+ virtual void deliverTo(const boost::shared_ptr<Queue>& queue);
+
+ virtual ~TxPublish(){}
+ virtual void accept(TxOpConstVisitor& visitor) const { visitor(*this); }
+
+ uint64_t contentSize();
+
+ boost::intrusive_ptr<Message> getMessage() const { return msg; }
+ const std::list<Queue::shared_ptr> getQueues() const { return queues; }
+ };
+ }
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/broker/Vhost.cpp b/RC9/qpid/cpp/src/qpid/broker/Vhost.cpp
new file mode 100644
index 0000000000..c5bb6c5104
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/Vhost.cpp
@@ -0,0 +1,48 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+#include "Vhost.h"
+#include "qpid/agent/ManagementAgent.h"
+
+using namespace qpid::broker;
+using qpid::management::ManagementAgent;
+namespace _qmf = qmf::org::apache::qpid::broker;
+
+namespace qpid { namespace management {
+class Manageable;
+}}
+
+Vhost::Vhost (qpid::management::Manageable* parentBroker) : mgmtObject(0)
+{
+ if (parentBroker != 0)
+ {
+ ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+
+ if (agent != 0)
+ {
+ mgmtObject = new _qmf::Vhost(agent, this, parentBroker, "/");
+ agent->addObject (mgmtObject, 0x1000000000000003LL);
+ }
+ }
+}
+
+void Vhost::setFederationTag(const std::string& tag)
+{
+ mgmtObject->set_federationTag(tag);
+}
diff --git a/RC9/qpid/cpp/src/qpid/broker/Vhost.h b/RC9/qpid/cpp/src/qpid/broker/Vhost.h
new file mode 100644
index 0000000000..ef59362e4d
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/Vhost.h
@@ -0,0 +1,49 @@
+#ifndef _Vhost_
+#define _Vhost_
+
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+#include "qpid/management/Manageable.h"
+#include "qmf/org/apache/qpid/broker/Vhost.h"
+#include <boost/shared_ptr.hpp>
+
+namespace qpid {
+namespace broker {
+
+class Vhost : public management::Manageable
+{
+ private:
+
+ qmf::org::apache::qpid::broker::Vhost* mgmtObject;
+
+ public:
+
+ typedef boost::shared_ptr<Vhost> shared_ptr;
+
+ Vhost (management::Manageable* parentBroker);
+
+ management::ManagementObject* GetManagementObject (void) const
+ { return mgmtObject; }
+ void setFederationTag(const std::string& tag);
+};
+
+}}
+
+#endif /*!_Vhost_*/
diff --git a/RC9/qpid/cpp/src/qpid/broker/posix/BrokerDefaults.cpp b/RC9/qpid/cpp/src/qpid/broker/posix/BrokerDefaults.cpp
new file mode 100644
index 0000000000..b3ef48fe58
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/posix/BrokerDefaults.cpp
@@ -0,0 +1,30 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/broker/Broker.h"
+
+namespace qpid {
+namespace broker {
+
+const std::string Broker::Options::DEFAULT_DATA_DIR_LOCATION("/tmp");
+const std::string Broker::Options::DEFAULT_DATA_DIR_NAME("/.qpidd");
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/broker/windows/BrokerDefaults.cpp b/RC9/qpid/cpp/src/qpid/broker/windows/BrokerDefaults.cpp
new file mode 100644
index 0000000000..138995980a
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/windows/BrokerDefaults.cpp
@@ -0,0 +1,30 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/broker/Broker.h"
+
+namespace qpid {
+namespace broker {
+
+const std::string Broker::Options::DEFAULT_DATA_DIR_LOCATION("\\TEMP");
+const std::string Broker::Options::DEFAULT_DATA_DIR_NAME("\\QPIDD.DATA");
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/broker/windows/SaslAuthenticator.cpp b/RC9/qpid/cpp/src/qpid/broker/windows/SaslAuthenticator.cpp
new file mode 100644
index 0000000000..a239987c0e
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/broker/windows/SaslAuthenticator.cpp
@@ -0,0 +1,175 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+// This source is only used on Windows; SSPI is the Windows mechanism for
+// accessing authentication mechanisms, analogous to Cyrus SASL.
+
+#include "qpid/broker/Connection.h"
+#include "qpid/log/Statement.h"
+#include "qpid/framing/reply_exceptions.h"
+
+#include <windows.h>
+
+using namespace qpid::framing;
+
+namespace qpid {
+namespace broker {
+
+class NullAuthenticator : public SaslAuthenticator
+{
+ Connection& connection;
+ framing::AMQP_ClientProxy::Connection client;
+public:
+ NullAuthenticator(Connection& connection);
+ ~NullAuthenticator();
+ void getMechanisms(framing::Array& mechanisms);
+ void start(const std::string& mechanism, const std::string& response);
+ void step(const std::string&) {}
+};
+
+class SspiAuthenticator : public SaslAuthenticator
+{
+ HANDLE userToken;
+ Connection& connection;
+ framing::AMQP_ClientProxy::Connection client;
+
+public:
+ SspiAuthenticator(Connection& connection);
+ ~SspiAuthenticator();
+ void getMechanisms(framing::Array& mechanisms);
+ void start(const std::string& mechanism, const std::string& response);
+ void step(const std::string& response);
+};
+
+bool SaslAuthenticator::available(void)
+{
+ return true;
+}
+
+// Initialize the SASL mechanism; throw if it fails.
+void SaslAuthenticator::init(const std::string& /*saslName*/)
+{
+ return;
+}
+
+void SaslAuthenticator::fini(void)
+{
+ return;
+}
+
+std::auto_ptr<SaslAuthenticator> SaslAuthenticator::createAuthenticator(Connection& c)
+{
+ if (c.getBroker().getOptions().auth) {
+ return std::auto_ptr<SaslAuthenticator>(new SspiAuthenticator(c));
+ } else {
+ return std::auto_ptr<SaslAuthenticator>(new NullAuthenticator(c));
+ }
+}
+
+NullAuthenticator::NullAuthenticator(Connection& c) : connection(c), client(c.getOutput()) {}
+NullAuthenticator::~NullAuthenticator() {}
+
+void NullAuthenticator::getMechanisms(Array& mechanisms)
+{
+ mechanisms.add(boost::shared_ptr<FieldValue>(new Str16Value("ANONYMOUS")));
+}
+
+void NullAuthenticator::start(const string& mechanism, const string& response)
+{
+ QPID_LOG(warning, "SASL: No Authentication Performed");
+ if (mechanism == "PLAIN") { // Old behavior
+ if (response.size() > 0 && response[0] == (char) 0) {
+ string temp = response.substr(1);
+ string::size_type i = temp.find((char)0);
+ string uid = temp.substr(0, i);
+ string pwd = temp.substr(i + 1);
+ connection.setUserId(uid);
+ }
+ } else {
+ connection.setUserId("anonymous");
+ }
+ client.tune(framing::CHANNEL_MAX, connection.getFrameMax(), 0, 0);
+}
+
+
+SspiAuthenticator::SspiAuthenticator(Connection& c) : userToken(INVALID_HANDLE_VALUE), connection(c), client(c.getOutput())
+{
+}
+
+SspiAuthenticator::~SspiAuthenticator()
+{
+ if (INVALID_HANDLE_VALUE != userToken) {
+ CloseHandle(userToken);
+ userToken = INVALID_HANDLE_VALUE;
+ }
+}
+
+void SspiAuthenticator::getMechanisms(Array& mechanisms)
+{
+ mechanisms.add(boost::shared_ptr<FieldValue>(new Str16Value(string("ANONYMOUS"))));
+ mechanisms.add(boost::shared_ptr<FieldValue>(new Str16Value(string("PLAIN"))));
+ QPID_LOG(info, "SASL: Mechanism list: ANONYMOUS PLAIN");
+}
+
+void SspiAuthenticator::start(const string& mechanism, const string& response)
+{
+ QPID_LOG(info, "SASL: Starting authentication with mechanism: " << mechanism);
+ if (mechanism == "ANONYMOUS") {
+ connection.setUserId("anonymous");
+ client.tune(framing::CHANNEL_MAX, connection.getFrameMax(), 0, 0);
+ return;
+ }
+ if (mechanism != "PLAIN")
+ throw ConnectionForcedException("Unsupported mechanism");
+
+ // PLAIN's response is composed of 3 strings separated by 0 bytes:
+ // authorization id, authentication id (user), clear-text password.
+ if (response.size() == 0)
+ throw ConnectionForcedException("Authentication failed");
+
+ string::size_type i = response.find((char)0);
+ string auth = response.substr(0, i);
+ string::size_type j = response.find((char)0, i+1);
+ string uid = response.substr(i+1, j-1);
+ string pwd = response.substr(j+1);
+ int error = 0;
+ if (!LogonUser(uid.c_str(), ".", pwd.c_str(),
+ LOGON32_LOGON_NETWORK,
+ LOGON32_PROVIDER_DEFAULT,
+ &userToken))
+ error = GetLastError();
+ pwd.replace(0, string::npos, 1, (char)0);
+ if (error != 0) {
+ QPID_LOG(info,
+ "SASL: Auth failed [" << error << "]: " << qpid::sys::strError(error));
+ throw ConnectionForcedException("Authentication failed");
+ }
+
+ connection.setUserId(uid);
+ client.tune(framing::CHANNEL_MAX, connection.getFrameMax(), 0, 0);
+}
+
+void SspiAuthenticator::step(const string& response)
+{
+ QPID_LOG(info, "SASL: Need another step!!!");
+}
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/client/AckMode.h b/RC9/qpid/cpp/src/qpid/client/AckMode.h
new file mode 100644
index 0000000000..b411c322d8
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/AckMode.h
@@ -0,0 +1,53 @@
+#ifndef _client_AckMode_h
+#define _client_AckMode_h
+
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+namespace qpid {
+namespace client {
+
+/**
+ * DEPRECATED
+ *
+ * The available acknowledgement modes for Channel (now also deprecated).
+ */
+enum AckMode {
+ /** No acknowledgement will be sent, broker can
+ discard messages as soon as they are delivered
+ to a consumer using this mode. **/
+ NO_ACK = 0,
+ /** Each message will be automatically
+ acknowledged as soon as it is delivered to the
+ application. **/
+ AUTO_ACK = 1,
+ /** Acknowledgements will be sent automatically,
+ but not for each message. **/
+ LAZY_ACK = 2,
+ /** The application is responsible for explicitly
+ acknowledging messages. **/
+ CLIENT_ACK = 3
+};
+
+}} // namespace qpid::client
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/client/AsyncSession.h b/RC9/qpid/cpp/src/qpid/client/AsyncSession.h
new file mode 100644
index 0000000000..150aabe191
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/AsyncSession.h
@@ -0,0 +1,38 @@
+#ifndef QPID_CLIENT_ASYNCSESSION_H
+#define QPID_CLIENT_ASYNCSESSION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/client/AsyncSession_0_10.h"
+
+namespace qpid {
+namespace client {
+
+/**
+ * AsyncSession is an alias for Session_0_10
+ *
+ * \ingroup clientapi
+ */
+typedef AsyncSession_0_10 AsyncSession;
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_ASYNCSESSION_H*/
diff --git a/RC9/qpid/cpp/src/qpid/client/Bounds.cpp b/RC9/qpid/cpp/src/qpid/client/Bounds.cpp
new file mode 100644
index 0000000000..e2ddb5dfec
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/Bounds.cpp
@@ -0,0 +1,71 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "Bounds.h"
+
+#include "qpid/log/Statement.h"
+#include "qpid/sys/Waitable.h"
+
+namespace qpid {
+namespace client {
+
+using sys::Waitable;
+
+Bounds::Bounds(size_t maxSize) : max(maxSize), current(0) {}
+
+bool Bounds::expand(size_t sizeRequired, bool block) {
+ if (!max) return true;
+ Waitable::ScopedLock l(lock);
+ current += sizeRequired;
+ if (block) {
+ Waitable::ScopedWait w(lock);
+ while (current > max)
+ lock.wait();
+ }
+ return current <= max;
+}
+
+void Bounds::reduce(size_t size) {
+ if (!max || size == 0) return;
+ Waitable::ScopedLock l(lock);
+ if (current == 0) return;
+ current -= std::min(size, current);
+ if (current < max && lock.hasWaiters()) {
+ lock.notifyAll();
+ }
+}
+
+size_t Bounds::getCurrentSize() {
+ Waitable::ScopedLock l(lock);
+ return current;
+}
+
+std::ostream& operator<<(std::ostream& out, const Bounds& bounds) {
+ out << "current=" << bounds.current << ", max=" << bounds.max << " [" << &bounds << "]";
+ return out;
+}
+
+void Bounds::setException(const sys::ExceptionHolder& e) {
+ Waitable::ScopedLock l(lock);
+ lock.setException(e);
+ lock.waitWaiters(); // Wait for waiting threads to exit.
+}
+
+}} // namespace qpid::client
diff --git a/RC9/qpid/cpp/src/qpid/client/Bounds.h b/RC9/qpid/cpp/src/qpid/client/Bounds.h
new file mode 100644
index 0000000000..838fcb8368
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/Bounds.h
@@ -0,0 +1,49 @@
+#ifndef QPID_CLIENT_BOUNDSCHECKING_H
+#define QPID_CLIENT_BOUNDSCHECKING_H
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/sys/Waitable.h"
+
+namespace qpid{
+namespace client{
+
+class Bounds
+{
+ public:
+ Bounds(size_t maxSize);
+ bool expand(size_t, bool block);
+ void reduce(size_t);
+ size_t getCurrentSize();
+ void setException(const sys::ExceptionHolder&);
+
+ private:
+ friend std::ostream& operator<<(std::ostream&, const Bounds&);
+ sys::Waitable lock;
+ const size_t max;
+ size_t current;
+};
+
+std::ostream& operator<<(std::ostream&, const Bounds&);
+
+
+}}
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/client/ChainableFrameHandler.h b/RC9/qpid/cpp/src/qpid/client/ChainableFrameHandler.h
new file mode 100644
index 0000000000..29e16d53dc
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/ChainableFrameHandler.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef _ChainableFrameHandler_
+#define _ChainableFrameHandler_
+
+#include <boost/function.hpp>
+#include "qpid/framing/AMQFrame.h"
+
+namespace qpid {
+namespace client {
+
+struct ChainableFrameHandler
+{
+ typedef boost::function<void(framing::AMQFrame&)> FrameDelegate;
+
+ FrameDelegate in;
+ FrameDelegate out;
+
+ ChainableFrameHandler() {}
+ ChainableFrameHandler(FrameDelegate i, FrameDelegate o): in(i), out(o) {}
+ virtual ~ChainableFrameHandler() {}
+};
+
+}}
+
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/client/Completion.h b/RC9/qpid/cpp/src/qpid/client/Completion.h
new file mode 100644
index 0000000000..c4979d7934
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/Completion.h
@@ -0,0 +1,71 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef _Completion_
+#define _Completion_
+
+#include <boost/shared_ptr.hpp>
+#include "Future.h"
+#include "SessionImpl.h"
+
+namespace qpid {
+namespace client {
+
+/**
+ * Asynchronous commands that do not return a result will return a
+ * Completion. You can use the completion to wait for that specific
+ * command to complete.
+ *
+ *@see TypedResult
+ *
+ *\ingroup clientapi
+ */
+class Completion
+{
+protected:
+ Future future;
+ shared_ptr<SessionImpl> session;
+
+public:
+ ///@internal
+ Completion() {}
+
+ ///@internal
+ Completion(Future f, shared_ptr<SessionImpl> s) : future(f), session(s) {}
+
+ /** Wait for the asynchronous command that returned this
+ *Completion to complete.
+ *
+ *@exception If the command returns an error, get() throws an exception.
+ */
+ void wait()
+ {
+ future.wait(*session);
+ }
+
+ bool isComplete() {
+ return future.isComplete(*session);
+ }
+};
+
+}}
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/client/Connection.cpp b/RC9/qpid/cpp/src/qpid/client/Connection.cpp
new file mode 100644
index 0000000000..f450344aa7
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/Connection.cpp
@@ -0,0 +1,145 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "Connection.h"
+#include "ConnectionSettings.h"
+#include "Message.h"
+#include "SessionImpl.h"
+#include "SessionBase_0_10Access.h"
+#include "qpid/Url.h"
+#include "qpid/log/Logger.h"
+#include "qpid/log/Options.h"
+#include "qpid/log/Statement.h"
+#include "qpid/shared_ptr.h"
+#include "qpid/framing/AMQP_HighestVersion.h"
+
+#include <algorithm>
+#include <iostream>
+#include <sstream>
+#include <functional>
+#include <boost/format.hpp>
+#include <boost/bind.hpp>
+
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+
+namespace qpid {
+namespace client {
+
+Connection::Connection() : version(framing::highestProtocolVersion) {}
+
+Connection::~Connection(){ }
+
+void Connection::open(
+ const Url& url,
+ const std::string& uid, const std::string& pwd,
+ const std::string& vhost,
+ uint16_t maxFrameSize)
+{
+ if (url.empty())
+ throw Exception(QPID_MSG("Attempt to open URL with no addresses."));
+ Url::const_iterator i = url.begin();
+ do {
+ const TcpAddress* tcp = i->get<TcpAddress>();
+ i++;
+ if (tcp) {
+ try {
+ ConnectionSettings settings;
+ settings.host = tcp->host;
+ settings.port = tcp->port;
+ settings.username = uid;
+ settings.password = pwd;
+ settings.virtualhost = vhost;
+ settings.maxFrameSize = maxFrameSize;
+ open(settings);
+ break;
+ }
+ catch (const Exception& /*e*/) {
+ if (i == url.end()) throw;
+ }
+ }
+ } while (i != url.end());
+}
+
+void Connection::open(
+ const std::string& host, int port,
+ const std::string& uid, const std::string& pwd,
+ const std::string& vhost,
+ uint16_t maxFrameSize)
+{
+ ConnectionSettings settings;
+ settings.host = host;
+ settings.port = port;
+ settings.username = uid;
+ settings.password = pwd;
+ settings.virtualhost = vhost;
+ settings.maxFrameSize = maxFrameSize;
+ open(settings);
+}
+
+bool Connection::isOpen() const {
+ return impl && impl->isOpen();
+}
+
+void
+Connection::registerFailureCallback ( boost::function<void ()> fn ) {
+ failureCallback = fn;
+ if ( impl )
+ impl->registerFailureCallback ( fn );
+}
+
+
+
+void Connection::open(const ConnectionSettings& settings)
+{
+ if (isOpen())
+ throw Exception(QPID_MSG("Connection::open() was already called"));
+
+ impl = shared_ptr<ConnectionImpl>(new ConnectionImpl(version, settings));
+ impl->open();
+ if ( failureCallback )
+ impl->registerFailureCallback ( failureCallback );
+}
+
+Session Connection::newSession(const std::string& name, uint32_t timeout) {
+ if (!isOpen())
+ throw Exception(QPID_MSG("Connection has not yet been opened"));
+ Session s;
+ SessionBase_0_10Access(s).set(impl->newSession(name, timeout));
+ return s;
+}
+
+void Connection::resume(Session& session) {
+ if (!isOpen())
+ throw Exception(QPID_MSG("Connection is not open."));
+ impl->addSession(session.impl);
+ session.impl->resume(impl);
+}
+
+void Connection::close() {
+ impl->close();
+}
+
+std::vector<Url> Connection::getKnownBrokers() {
+ return impl ? impl->getKnownBrokers() : std::vector<Url>();
+}
+
+}} // namespace qpid::client
diff --git a/RC9/qpid/cpp/src/qpid/client/Connection.h b/RC9/qpid/cpp/src/qpid/client/Connection.h
new file mode 100644
index 0000000000..d03542bb5b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/Connection.h
@@ -0,0 +1,185 @@
+#ifndef QPID_CLIENT_CONNECTION_H
+#define QPID_CLIENT_CONNECTION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <map>
+#include <string>
+#include "qpid/client/Session.h"
+
+namespace qpid {
+
+struct Url;
+
+namespace client {
+
+struct ConnectionSettings;
+class ConnectionImpl;
+
+/**
+ * Represents a connection to an AMQP broker. All communication is
+ * initiated by establishing a connection, then creating one or more
+ * Session objects using the connection. @see newSession()
+ *
+ * \ingroup clientapi
+ *
+ */
+class Connection
+{
+ framing::ProtocolVersion version;
+
+ boost::function<void ()> failureCallback;
+
+
+ protected:
+ boost::shared_ptr<ConnectionImpl> impl;
+
+
+ public:
+ /**
+ * Creates a connection object, but does not open the connection.
+ * @see open()
+ */
+ Connection();
+
+ ~Connection();
+
+ /**
+ * Opens a connection to a broker.
+ *
+ * @param host the host on which the broker is running.
+ *
+ * @param port the port on the which the broker is listening.
+ *
+ * @param uid the userid to connect with.
+ *
+ * @param pwd the password to connect with (currently SASL
+ * PLAIN is the only authentication method supported so this
+ * is sent in clear text).
+ *
+ * @param virtualhost the AMQP virtual host to use (virtual
+ * hosts, where implemented(!), provide namespace partitioning
+ * within a single broker).
+ */
+ void open(const std::string& host, int port = 5672,
+ const std::string& uid = "guest",
+ const std::string& pwd = "guest",
+ const std::string& virtualhost = "/", uint16_t maxFrameSize=65535);
+
+ /**
+ * Opens a connection to a broker using a URL.
+ * If the URL contains multiple addresses, try each in turn
+ * till connection is successful.
+ *
+ * @url address of the broker to connect to.
+ *
+ * @param uid the userid to connect with.
+ *
+ * @param pwd the password to connect with (currently SASL
+ * PLAIN is the only authentication method supported so this
+ * is sent in clear text).
+ *
+ * @param virtualhost the AMQP virtual host to use (virtual
+ * hosts, where implemented(!), provide namespace partitioning
+ * within a single broker).
+ */
+ void open(const Url& url,
+ const std::string& uid = "guest",
+ const std::string& pwd = "guest",
+ const std::string& virtualhost = "/", uint16_t maxFrameSize=65535);
+
+ /**
+ * Opens a connection to a broker.
+ *
+ * @param the settings to use (host, port etc). @see ConnectionSettings.
+ */
+ void open(const ConnectionSettings& settings);
+
+ /**
+ * Close the connection.
+ *
+ * Any further use of this connection (without reopening it) will
+ * not succeed.
+ */
+ void close();
+
+ /**
+ * Create a new session on this connection. Sessions allow
+ * multiple streams of work to be multiplexed over the same
+ * connection. The returned Session provides functions to send
+ * commands to the broker.
+ *
+ * Session functions are synchronous. In other words, a Session
+ * function will send a command to the broker and does not return
+ * until it receives the broker's response confirming the command
+ * was executed.
+ *
+ * AsyncSession provides asynchronous versions of the same
+ * functions. These functions send a command to the broker but do
+ * not wait for a response.
+ *
+ * You can convert a Session s into an AsyncSession as follows:
+ * @code
+ * #include <qpid/client/AsyncSession.h>
+ * AsyncSession as = async(s);
+ * @endcode
+ *
+ * You can execute a single command asynchronously will a Session s
+ * like ths:
+ * @code
+ * async(s).messageTransfer(...);
+ * @endcode
+ *
+ * Using an AsyncSession is faster for sending large numbers of
+ * commands, since each command is sent as soon as possible
+ * without waiting for the previous command to be confirmed.
+ *
+ * However with AsyncSession you cannot assume that a command has
+ * completed until you explicitly synchronize. The simplest way to
+ * do this is to call Session::sync() or AsyncSession::sync().
+ * Both of these functions wait for the broker to confirm all
+ * commands issued so far on the session.
+ *
+ *@param name: A name to identify the session. @see qpid::SessionId
+ * If the name is empty (the default) then a unique name will be
+ * chosen using a Universally-unique identifier (UUID) algorithm.
+ */
+ Session newSession(const std::string& name=std::string(), uint32_t timeoutSeconds = 0);
+
+ /**
+ * Resume a suspended session. A session may be resumed
+ * on a different connection to the one that created it.
+ */
+ void resume(Session& session);
+
+ bool isOpen() const;
+
+ std::vector<Url> getKnownBrokers();
+ void registerFailureCallback ( boost::function<void ()> fn );
+
+ friend class ConnectionAccess; ///<@internal
+ friend class SessionBase_0_10; ///<@internal
+};
+
+}} // namespace qpid::client
+
+
+#endif /*!QPID_CLIENT_CONNECTION_H*/
diff --git a/RC9/qpid/cpp/src/qpid/client/ConnectionAccess.h b/RC9/qpid/cpp/src/qpid/client/ConnectionAccess.h
new file mode 100644
index 0000000000..b662fd5d8b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/ConnectionAccess.h
@@ -0,0 +1,41 @@
+#ifndef QPID_CLIENT_CONNECTIONACCESS_H
+#define QPID_CLIENT_CONNECTIONACCESS_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/client/Connection.h"
+
+/**@file @internal Internal use only */
+
+namespace qpid {
+namespace client {
+
+
+
+struct ConnectionAccess {
+ static void setVersion(Connection& c, const framing::ProtocolVersion& v) { c.version = v; }
+ static boost::shared_ptr<ConnectionImpl> getImpl(Connection& c) { return c.impl; }
+};
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_CONNECTIONACCESS_H*/
diff --git a/RC9/qpid/cpp/src/qpid/client/ConnectionHandler.cpp b/RC9/qpid/cpp/src/qpid/client/ConnectionHandler.cpp
new file mode 100644
index 0000000000..db5d006a17
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/ConnectionHandler.cpp
@@ -0,0 +1,226 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "ConnectionHandler.h"
+
+#include "qpid/log/Statement.h"
+#include "qpid/framing/amqp_framing.h"
+#include "qpid/framing/all_method_bodies.h"
+#include "qpid/framing/ClientInvoker.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/log/Helpers.h"
+
+using namespace qpid::client;
+using namespace qpid::framing;
+using namespace qpid::framing::connection;
+
+namespace {
+const std::string OK("OK");
+const std::string PLAIN("PLAIN");
+const std::string en_US("en_US");
+
+const std::string INVALID_STATE_START("start received in invalid state");
+const std::string INVALID_STATE_TUNE("tune received in invalid state");
+const std::string INVALID_STATE_OPEN_OK("open-ok received in invalid state");
+const std::string INVALID_STATE_CLOSE_OK("close-ok received in invalid state");
+
+}
+
+CloseCode ConnectionHandler::convert(uint16_t replyCode)
+{
+ switch (replyCode) {
+ case 200: return CLOSE_CODE_NORMAL;
+ case 320: return CLOSE_CODE_CONNECTION_FORCED;
+ case 402: return CLOSE_CODE_INVALID_PATH;
+ case 501: default:
+ return CLOSE_CODE_FRAMING_ERROR;
+ }
+}
+
+ConnectionHandler::ConnectionHandler(const ConnectionSettings& s, ProtocolVersion& v)
+ : StateManager(NOT_STARTED), ConnectionSettings(s), outHandler(*this), proxy(outHandler),
+ errorCode(CLOSE_CODE_NORMAL), version(v)
+{
+ insist = true;
+
+ ESTABLISHED.insert(FAILED);
+ ESTABLISHED.insert(CLOSED);
+ ESTABLISHED.insert(OPEN);
+
+ FINISHED.insert(FAILED);
+ FINISHED.insert(CLOSED);
+}
+
+void ConnectionHandler::incoming(AMQFrame& frame)
+{
+ if (getState() == CLOSED) {
+ throw Exception("Received frame on closed connection");
+ }
+
+
+ AMQBody* body = frame.getBody();
+ try {
+ if (frame.getChannel() != 0 || !invoke(static_cast<ConnectionOperations&>(*this), *body)) {
+ switch(getState()) {
+ case OPEN:
+ in(frame);
+ break;
+ case CLOSING:
+ QPID_LOG(warning, "Ignoring frame while closing connection: " << frame);
+ break;
+ default:
+ throw Exception("Cannot receive frames on non-zero channel until connection is established.");
+ }
+ }
+ }catch(std::exception& e){
+ QPID_LOG(warning, "Closing connection due to " << e.what());
+ setState(CLOSING);
+ errorCode = CLOSE_CODE_FRAMING_ERROR;
+ errorText = e.what();
+ proxy.close(501, e.what());
+ }
+}
+
+void ConnectionHandler::outgoing(AMQFrame& frame)
+{
+ if (getState() == OPEN)
+ out(frame);
+ else
+ throw TransportFailure(errorText.empty() ? "Connection is not open." : errorText);
+}
+
+void ConnectionHandler::waitForOpen()
+{
+ waitFor(ESTABLISHED);
+ if (getState() == FAILED || getState() == CLOSED) {
+ throw ConnectionException(errorCode, errorText);
+ }
+}
+
+void ConnectionHandler::close()
+{
+ switch (getState()) {
+ case NEGOTIATING:
+ case OPENING:
+ fail("Connection closed before it was established");
+ break;
+ case OPEN:
+ setState(CLOSING);
+ proxy.close(200, OK);
+ waitFor(FINISHED);
+ break;
+ // Nothing to do for CLOSING, CLOSED, FAILED or NOT_STARTED
+ }
+}
+
+void ConnectionHandler::checkState(STATES s, const std::string& msg)
+{
+ if (getState() != s) {
+ throw CommandInvalidException(msg);
+ }
+}
+
+void ConnectionHandler::fail(const std::string& message)
+{
+ errorCode = CLOSE_CODE_FRAMING_ERROR;
+ errorText = message;
+ QPID_LOG(warning, message);
+ setState(FAILED);
+}
+
+void ConnectionHandler::start(const FieldTable& /*serverProps*/, const Array& /*mechanisms*/, const Array& /*locales*/)
+{
+ checkState(NOT_STARTED, INVALID_STATE_START);
+ setState(NEGOTIATING);
+ //TODO: verify that desired mechanism and locale are supported
+ string response = ((char)0) + username + ((char)0) + password;
+ proxy.startOk(properties, mechanism, response, locale);
+}
+
+void ConnectionHandler::secure(const std::string& /*challenge*/)
+{
+ throw NotImplementedException("Challenge-response cycle not yet implemented in client");
+}
+
+void ConnectionHandler::tune(uint16_t maxChannelsProposed, uint16_t maxFrameSizeProposed,
+ uint16_t /*heartbeatMin*/, uint16_t /*heartbeatMax*/)
+{
+ checkState(NEGOTIATING, INVALID_STATE_TUNE);
+ maxChannels = std::min(maxChannels, maxChannelsProposed);
+ maxFrameSize = std::min(maxFrameSize, maxFrameSizeProposed);
+ //TODO: implement heartbeats and check desired value is in valid range
+ proxy.tuneOk(maxChannels, maxFrameSize, heartbeat);
+ setState(OPENING);
+ proxy.open(virtualhost, capabilities, insist);
+}
+
+void ConnectionHandler::openOk ( const Array& knownBrokers )
+{
+ checkState(OPENING, INVALID_STATE_OPEN_OK);
+ knownBrokersUrls.clear();
+ framing::Array::ValueVector::const_iterator i;
+ for ( i = knownBrokers.begin(); i != knownBrokers.end(); ++i )
+ knownBrokersUrls.push_back(Url((*i)->get<std::string>()));
+ setState(OPEN);
+ QPID_LOG(debug, "Known-brokers for connection: " << log::formatList(knownBrokersUrls));
+}
+
+
+void ConnectionHandler::redirect(const std::string& /*host*/, const Array& /*knownHosts*/)
+{
+ throw NotImplementedException("Redirection received from broker; not yet implemented in client");
+}
+
+void ConnectionHandler::close(uint16_t replyCode, const std::string& replyText)
+{
+ proxy.closeOk();
+ errorCode = convert(replyCode);
+ errorText = replyText;
+ setState(CLOSED);
+ QPID_LOG(warning, "Broker closed connection: " << replyCode << ", " << replyText);
+ if (onError) {
+ onError(replyCode, replyText);
+ }
+}
+
+void ConnectionHandler::closeOk()
+{
+ checkState(CLOSING, INVALID_STATE_CLOSE_OK);
+ if (onError && errorCode != CLOSE_CODE_NORMAL) {
+ onError(errorCode, errorText);
+ } else if (onClose) {
+ onClose();
+ }
+ setState(CLOSED);
+}
+
+bool ConnectionHandler::isOpen() const
+{
+ return getState() == OPEN;
+}
+
+bool ConnectionHandler::isClosed() const
+{
+ int s = getState();
+ return s == CLOSED || s == FAILED;
+}
+
+bool ConnectionHandler::isClosing() const { return getState() == CLOSING; }
diff --git a/RC9/qpid/cpp/src/qpid/client/ConnectionHandler.h b/RC9/qpid/cpp/src/qpid/client/ConnectionHandler.h
new file mode 100644
index 0000000000..12323684a5
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/ConnectionHandler.h
@@ -0,0 +1,116 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _ConnectionHandler_
+#define _ConnectionHandler_
+
+#include "ChainableFrameHandler.h"
+#include "ConnectionSettings.h"
+#include "StateManager.h"
+#include "qpid/framing/AMQMethodBody.h"
+#include "qpid/framing/AMQP_HighestVersion.h"
+#include "qpid/framing/AMQP_ClientOperations.h"
+#include "qpid/framing/AMQP_ServerProxy.h"
+#include "qpid/framing/Array.h"
+#include "qpid/framing/enum.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/FrameHandler.h"
+#include "qpid/framing/InputHandler.h"
+#include "qpid/Url.h"
+
+namespace qpid {
+namespace client {
+
+class ConnectionHandler : private StateManager,
+ public ConnectionSettings,
+ public ChainableFrameHandler,
+ public framing::InputHandler,
+ private framing::AMQP_ClientOperations::ConnectionHandler
+{
+ typedef framing::AMQP_ClientOperations::ConnectionHandler ConnectionOperations;
+ enum STATES {NOT_STARTED, NEGOTIATING, OPENING, OPEN, CLOSING, CLOSED, FAILED};
+ std::set<int> ESTABLISHED, FINISHED;
+
+ class Adapter : public framing::FrameHandler
+ {
+ ConnectionHandler& handler;
+ public:
+ Adapter(ConnectionHandler& h) : handler(h) {}
+ void handle(framing::AMQFrame& f) { handler.out(f); }
+ };
+
+ Adapter outHandler;
+ framing::AMQP_ServerProxy::Connection proxy;
+ framing::connection::CloseCode errorCode;
+ std::string errorText;
+ bool insist;
+ framing::ProtocolVersion version;
+ framing::Array capabilities;
+ framing::FieldTable properties;
+
+ void checkState(STATES s, const std::string& msg);
+
+ //methods corresponding to connection controls:
+ void start(const framing::FieldTable& serverProperties,
+ const framing::Array& mechanisms,
+ const framing::Array& locales);
+ void secure(const std::string& challenge);
+ void tune(uint16_t channelMax,
+ uint16_t frameMax,
+ uint16_t heartbeatMin,
+ uint16_t heartbeatMax);
+ void openOk(const framing::Array& knownHosts);
+ void redirect(const std::string& host,
+ const framing::Array& knownHosts);
+ void close(uint16_t replyCode, const std::string& replyText);
+ void closeOk();
+
+public:
+ using InputHandler::handle;
+ typedef boost::function<void()> CloseListener;
+ typedef boost::function<void(uint16_t, const std::string&)> ErrorListener;
+
+ ConnectionHandler(const ConnectionSettings&, framing::ProtocolVersion&);
+
+ void received(framing::AMQFrame& f) { incoming(f); }
+
+ void incoming(framing::AMQFrame& frame);
+ void outgoing(framing::AMQFrame& frame);
+
+ void waitForOpen();
+ void close();
+ void fail(const std::string& message);
+
+ // Note that open and closed aren't related by open = !closed
+ bool isOpen() const;
+ bool isClosed() const;
+ bool isClosing() const;
+
+ CloseListener onClose;
+ ErrorListener onError;
+
+ std::vector<Url> knownBrokersUrls;
+
+ static framing::connection::CloseCode convert(uint16_t replyCode);
+};
+
+}}
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/client/ConnectionImpl.cpp b/RC9/qpid/cpp/src/qpid/client/ConnectionImpl.cpp
new file mode 100644
index 0000000000..0d7ffa0288
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/ConnectionImpl.cpp
@@ -0,0 +1,201 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "ConnectionImpl.h"
+#include "Connector.h"
+#include "ConnectionSettings.h"
+#include "SessionImpl.h"
+#include "FailoverListener.h"
+
+#include "qpid/log/Statement.h"
+#include "qpid/Url.h"
+#include "qpid/framing/enum.h"
+#include "qpid/framing/reply_exceptions.h"
+
+#include <boost/bind.hpp>
+#include <boost/format.hpp>
+
+
+namespace qpid {
+namespace client {
+
+using namespace qpid::framing;
+using namespace qpid::framing::connection;
+using namespace qpid::sys;
+using namespace qpid::framing::connection;//for connection error codes
+
+ConnectionImpl::ConnectionImpl(framing::ProtocolVersion v, const ConnectionSettings& settings)
+ : Bounds(settings.maxFrameSize * settings.bounds),
+ handler(settings, v),
+ version(v),
+ nextChannel(1)
+{
+ QPID_LOG(debug, "ConnectionImpl created for " << version.toString());
+ handler.in = boost::bind(&ConnectionImpl::incoming, this, _1);
+ handler.out = boost::bind(&Connector::send, boost::ref(connector), _1);
+ handler.onClose = boost::bind(&ConnectionImpl::closed, this,
+ CLOSE_CODE_NORMAL, std::string());
+ //only set error handler once open
+ handler.onError = boost::bind(&ConnectionImpl::closed, this, _1, _2);
+}
+
+ConnectionImpl::~ConnectionImpl() {
+ // Important to close the connector first, to ensure the
+ // connector thread does not call on us while the destructor
+ // is running.
+ failover.reset();
+ if (connector) connector->close();
+}
+
+void ConnectionImpl::addSession(const boost::shared_ptr<SessionImpl>& session, uint16_t channel)
+{
+ Mutex::ScopedLock l(lock);
+ session->setChannel(channel ? channel : nextChannel++);
+ boost::weak_ptr<SessionImpl>& s = sessions[session->getChannel()];
+ boost::shared_ptr<SessionImpl> ss = s.lock();
+ if (ss) throw SessionBusyException(QPID_MSG("Channel " << ss->getChannel() << " attachd to " << ss->getId()));
+ s = session;
+}
+
+void ConnectionImpl::handle(framing::AMQFrame& frame)
+{
+ handler.outgoing(frame);
+}
+
+void ConnectionImpl::incoming(framing::AMQFrame& frame)
+{
+ boost::shared_ptr<SessionImpl> s;
+ {
+ Mutex::ScopedLock l(lock);
+ s = sessions[frame.getChannel()].lock();
+ }
+ if (!s)
+ throw NotAttachedException(QPID_MSG("Invalid channel: " << frame.getChannel()));
+ s->in(frame);
+}
+
+bool ConnectionImpl::isOpen() const
+{
+ return handler.isOpen();
+}
+
+
+void ConnectionImpl::open()
+{
+ const std::string& protocol = handler.protocol;
+ const std::string& host = handler.host;
+ int port = handler.port;
+ QPID_LOG(info, "Connecting to " << protocol << ":" << host << ":" << port);
+
+ connector.reset(Connector::create(protocol, version, handler, this));
+ connector->setInputHandler(&handler);
+ connector->setShutdownHandler(this);
+ connector->connect(host, port);
+ connector->init();
+ handler.waitForOpen();
+
+ failover.reset(new FailoverListener(shared_from_this(), handler.knownBrokersUrls));
+}
+
+void ConnectionImpl::idleIn()
+{
+ close();
+}
+
+void ConnectionImpl::idleOut()
+{
+ AMQFrame frame(in_place<AMQHeartbeatBody>());
+ connector->send(frame);
+}
+
+void ConnectionImpl::close()
+{
+ if (!handler.isOpen()) return;
+ handler.close();
+ closed(CLOSE_CODE_NORMAL, "Closed by client");
+}
+
+
+template <class F> void ConnectionImpl::closeInternal(const F& f) {
+ {
+ Mutex::ScopedUnlock u(lock);
+ connector->close();
+ }
+ //notifying sessions of failure can result in those session being
+ //deleted which in turn results in a call to erase(); this can
+ //even happen on this thread, when 's' goes out of scope
+ //below. Using a copy prevents the map being modified as we
+ //iterate through.
+ SessionMap copy;
+ sessions.swap(copy);
+ for (SessionMap::iterator i = copy.begin(); i != copy.end(); ++i) {
+ boost::shared_ptr<SessionImpl> s = i->second.lock();
+ if (s) f(s);
+ }
+}
+
+void ConnectionImpl::closed(uint16_t code, const std::string& text) {
+ Mutex::ScopedLock l(lock);
+ setException(new ConnectionException(ConnectionHandler::convert(code), text));
+ closeInternal(boost::bind(&SessionImpl::connectionClosed, _1, code, text));
+}
+
+static const std::string CONN_CLOSED("Connection closed");
+
+void ConnectionImpl::shutdown() {
+ if ( failureCallback )
+ failureCallback();
+
+ if (handler.isClosed()) return;
+
+ // FIXME aconway 2008-06-06: exception use, amqp0-10 does not seem to have
+ // an appropriate close-code. connection-forced is not right.
+ bool isClosing = handler.isClosing();
+ handler.fail(CONN_CLOSED);//ensure connection is marked as failed before notifying sessions
+ Mutex::ScopedLock l(lock);
+ if (!isClosing)
+ closeInternal(boost::bind(&SessionImpl::connectionBroke, _1, CONN_CLOSED));
+ setException(new TransportFailure(CONN_CLOSED));
+}
+
+void ConnectionImpl::erase(uint16_t ch) {
+ Mutex::ScopedLock l(lock);
+ sessions.erase(ch);
+}
+
+const ConnectionSettings& ConnectionImpl::getNegotiatedSettings()
+{
+ return handler;
+}
+
+std::vector<qpid::Url> ConnectionImpl::getKnownBrokers() {
+ return failover ? failover->getKnownBrokers() : handler.knownBrokersUrls;
+}
+
+boost::shared_ptr<SessionImpl> ConnectionImpl::newSession(const std::string& name, uint32_t timeout, uint16_t channel) {
+ boost::shared_ptr<SessionImpl> simpl(new SessionImpl(name, shared_from_this()));
+ addSession(simpl, channel);
+ simpl->open(timeout);
+ return simpl;
+}
+
+void ConnectionImpl::stopFailoverListener() { failover->stop(); }
+
+}} // namespace qpid::client
diff --git a/RC9/qpid/cpp/src/qpid/client/ConnectionImpl.h b/RC9/qpid/cpp/src/qpid/client/ConnectionImpl.h
new file mode 100644
index 0000000000..55a4929028
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/ConnectionImpl.h
@@ -0,0 +1,99 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef _ConnectionImpl_
+#define _ConnectionImpl_
+
+#include "Bounds.h"
+#include "ConnectionHandler.h"
+
+#include "qpid/framing/FrameHandler.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/ShutdownHandler.h"
+#include "qpid/sys/TimeoutHandler.h"
+
+#include <map>
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+
+namespace qpid {
+namespace client {
+
+class Connector;
+struct ConnectionSettings;
+class SessionImpl;
+class FailoverListener;
+
+class ConnectionImpl : public Bounds,
+ public framing::FrameHandler,
+ public sys::TimeoutHandler,
+ public sys::ShutdownHandler,
+ public boost::enable_shared_from_this<ConnectionImpl>
+
+{
+ typedef std::map<uint16_t, boost::weak_ptr<SessionImpl> > SessionMap;
+
+ SessionMap sessions;
+ ConnectionHandler handler;
+ boost::scoped_ptr<Connector> connector;
+ boost::scoped_ptr<FailoverListener> failover;
+ framing::ProtocolVersion version;
+ uint16_t nextChannel;
+ sys::Mutex lock;
+
+ template <class F> void closeInternal(const F&);
+
+ void incoming(framing::AMQFrame& frame);
+ void closed(uint16_t, const std::string&);
+ void idleOut();
+ void idleIn();
+ void shutdown();
+
+ boost::function<void ()> failureCallback;
+
+ public:
+ ConnectionImpl(framing::ProtocolVersion version, const ConnectionSettings& settings);
+ ~ConnectionImpl();
+
+ void open();
+ bool isOpen() const;
+
+ boost::shared_ptr<SessionImpl> newSession(const std::string& name, uint32_t timeout, uint16_t channel=0);
+ void addSession(const boost::shared_ptr<SessionImpl>&, uint16_t channel=0);
+
+ void close();
+ void handle(framing::AMQFrame& frame);
+ void erase(uint16_t channel);
+ const ConnectionSettings& getNegotiatedSettings();
+
+ std::vector<Url> getKnownBrokers();
+ void registerFailureCallback ( boost::function<void ()> fn ) { failureCallback = fn; }
+ void stopFailoverListener();
+
+ framing::ProtocolVersion getVersion() { return version; }
+};
+
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/client/ConnectionSettings.cpp b/RC9/qpid/cpp/src/qpid/client/ConnectionSettings.cpp
new file mode 100644
index 0000000000..f5fc62dad2
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/ConnectionSettings.cpp
@@ -0,0 +1,54 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "ConnectionSettings.h"
+
+#include "qpid/log/Logger.h"
+#include "qpid/sys/Socket.h"
+
+namespace qpid {
+namespace client {
+
+ConnectionSettings::ConnectionSettings() :
+ protocol("tcp"),
+ host("localhost"),
+ port(TcpAddress::DEFAULT_PORT),
+ username("guest"),
+ password("guest"),
+ mechanism("PLAIN"),
+ locale("en_US"),
+ heartbeat(0),
+ maxChannels(32767),
+ maxFrameSize(65535),
+ bounds(2),
+ tcpNoDelay(false)
+{}
+
+ConnectionSettings::~ConnectionSettings() {}
+
+void ConnectionSettings::configureSocket(qpid::sys::Socket& socket) const
+{
+ if (tcpNoDelay) {
+ socket.setTcpNoDelay(tcpNoDelay);
+ QPID_LOG(info, "Set TCP_NODELAY");
+ }
+}
+
+}} // namespace qpid::client
diff --git a/RC9/qpid/cpp/src/qpid/client/ConnectionSettings.h b/RC9/qpid/cpp/src/qpid/client/ConnectionSettings.h
new file mode 100644
index 0000000000..1b994a6da3
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/ConnectionSettings.h
@@ -0,0 +1,118 @@
+#ifndef QPID_CLIENT_CONNECTIONSETTINGS_H
+#define QPID_CLIENT_CONNECTIONSETTINGS_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/Options.h"
+#include "qpid/log/Options.h"
+#include "qpid/Url.h"
+
+#include <iostream>
+#include <exception>
+
+namespace qpid {
+
+namespace sys {
+class Socket;
+}
+
+namespace client {
+
+/**
+ * Settings for a Connection.
+ */
+struct ConnectionSettings {
+
+ ConnectionSettings();
+ virtual ~ConnectionSettings();
+
+ /**
+ * Allows socket to be configured; default only sets tcp-nodelay
+ * based on the flag set. Can be overridden.
+ */
+ virtual void configureSocket(qpid::sys::Socket&) const;
+
+ /**
+ * The protocol used for the connection (defaults to 'tcp')
+ */
+ std::string protocol;
+
+ /**
+ * The host (or ip address) to connect to (defaults to 'localhost').
+ */
+ std::string host;
+ /**
+ * The port to connect to (defaults to 5672).
+ */
+ uint16_t port;
+ /**
+ * Allows an AMQP 'virtual host' to be specified for the
+ * connection.
+ */
+ std::string virtualhost;
+
+ /**
+ * The username to use when authenticating the connection.
+ */
+ std::string username;
+ /**
+ * The password to use when authenticating the connection.
+ */
+ std::string password;
+ /**
+ * The SASL mechanism to use when authenticating the connection;
+ * the options are currently PLAIN or ANONYMOUS.
+ */
+ std::string mechanism;
+ /**
+ * Allows a locale to be specified for the connection.
+ */
+ std::string locale;
+ /**
+ * Allows a heartbeat frequency to be specified (this feature is
+ * not yet implemented).
+ */
+ uint16_t heartbeat;
+ /**
+ * The maximum number of channels that the client will request for
+ * use on this connection.
+ */
+ uint16_t maxChannels;
+ /**
+ * The maximum frame size that the client will request for this
+ * connection.
+ */
+ uint16_t maxFrameSize;
+ /**
+ * Limit the size of the connections send buffer . The buffer
+ * is limited to bounds * maxFrameSize.
+ */
+ uint bounds;
+ /**
+ * If true, TCP_NODELAY will be set for the connection.
+ */
+ bool tcpNoDelay;
+};
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_CONNECTIONSETTINGS_H*/
diff --git a/RC9/qpid/cpp/src/qpid/client/Connector.cpp b/RC9/qpid/cpp/src/qpid/client/Connector.cpp
new file mode 100644
index 0000000000..bef98863a1
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/Connector.cpp
@@ -0,0 +1,413 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "Connector.h"
+
+#include "Bounds.h"
+#include "ConnectionImpl.h"
+#include "ConnectionSettings.h"
+#include "qpid/log/Statement.h"
+#include "qpid/sys/Time.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/sys/AsynchIO.h"
+#include "qpid/sys/Dispatcher.h"
+#include "qpid/sys/Poller.h"
+#include "qpid/Msg.h"
+
+#include <iostream>
+#include <map>
+#include <boost/bind.hpp>
+#include <boost/format.hpp>
+#include <boost/weak_ptr.hpp>
+
+namespace qpid {
+namespace client {
+
+using namespace qpid::sys;
+using namespace qpid::framing;
+using boost::format;
+using boost::str;
+
+// Stuff for the registry of protocol connectors (maybe should be moved to its own file)
+namespace {
+ typedef std::map<std::string, Connector::Factory*> ProtocolRegistry;
+
+ ProtocolRegistry& theProtocolRegistry() {
+ static ProtocolRegistry protocolRegistry;
+
+ return protocolRegistry;
+ }
+}
+
+Connector* Connector::create(const std::string& proto, framing::ProtocolVersion v, const ConnectionSettings& s, ConnectionImpl* c)
+{
+ ProtocolRegistry::const_iterator i = theProtocolRegistry().find(proto);
+ if (i==theProtocolRegistry().end()) {
+ throw Exception(QPID_MSG("Unknown protocol: " << proto));
+ }
+ return (i->second)(v, s, c);
+}
+
+void Connector::registerFactory(const std::string& proto, Factory* connectorFactory)
+{
+ ProtocolRegistry::const_iterator i = theProtocolRegistry().find(proto);
+ if (i!=theProtocolRegistry().end()) {
+ QPID_LOG(error, "Tried to register protocol: " << proto << " more than once");
+ }
+ theProtocolRegistry()[proto] = connectorFactory;
+}
+
+class TCPConnector : public Connector, private sys::Runnable
+{
+ struct Buff;
+
+ /** Batch up frames for writing to aio. */
+ class Writer : public framing::FrameHandler {
+ typedef sys::AsynchIOBufferBase BufferBase;
+ typedef std::vector<framing::AMQFrame> Frames;
+
+ const uint16_t maxFrameSize;
+ sys::Mutex lock;
+ sys::AsynchIO* aio;
+ BufferBase* buffer;
+ Frames frames;
+ size_t lastEof; // Position after last EOF in frames
+ framing::Buffer encode;
+ size_t framesEncoded;
+ std::string identifier;
+ Bounds* bounds;
+
+ void writeOne();
+ void newBuffer();
+
+ public:
+
+ Writer(uint16_t maxFrameSize, Bounds*);
+ ~Writer();
+ void init(std::string id, sys::AsynchIO*);
+ void handle(framing::AMQFrame&);
+ void write(sys::AsynchIO&);
+ };
+
+ const uint16_t maxFrameSize;
+ framing::ProtocolVersion version;
+ bool initiated;
+
+ sys::Mutex closedLock;
+ bool closed;
+ bool joined;
+
+ sys::ShutdownHandler* shutdownHandler;
+ framing::InputHandler* input;
+ framing::InitiationHandler* initialiser;
+ framing::OutputHandler* output;
+
+ Writer writer;
+
+ sys::Thread receiver;
+
+ sys::Socket socket;
+
+ sys::AsynchIO* aio;
+ boost::shared_ptr<sys::Poller> poller;
+
+ ~TCPConnector();
+
+ void run();
+ void handleClosed();
+ bool closeInternal();
+
+ bool readbuff(qpid::sys::AsynchIO&, qpid::sys::AsynchIOBufferBase*);
+ void writebuff(qpid::sys::AsynchIO&);
+ void writeDataBlock(const framing::AMQDataBlock& data);
+ void eof(qpid::sys::AsynchIO&);
+
+ std::string identifier;
+
+ boost::weak_ptr<ConnectionImpl> impl;
+
+ void connect(const std::string& host, int port);
+ void init();
+ void close();
+ void send(framing::AMQFrame& frame);
+
+ void setInputHandler(framing::InputHandler* handler);
+ void setShutdownHandler(sys::ShutdownHandler* handler);
+ sys::ShutdownHandler* getShutdownHandler() const;
+ framing::OutputHandler* getOutputHandler();
+ const std::string& getIdentifier() const;
+
+public:
+ TCPConnector(framing::ProtocolVersion pVersion,
+ const ConnectionSettings&,
+ ConnectionImpl*);
+};
+
+// Static constructor which registers connector here
+namespace {
+ Connector* create(framing::ProtocolVersion v, const ConnectionSettings& s, ConnectionImpl* c) {
+ return new TCPConnector(v, s, c);
+ }
+
+ struct StaticInit {
+ StaticInit() {
+ Connector::registerFactory("tcp", &create);
+ };
+ } init;
+}
+
+TCPConnector::TCPConnector(ProtocolVersion ver,
+ const ConnectionSettings& settings,
+ ConnectionImpl* cimpl)
+ : maxFrameSize(settings.maxFrameSize),
+ version(ver),
+ initiated(false),
+ closed(true),
+ joined(true),
+ shutdownHandler(0),
+ writer(maxFrameSize, cimpl),
+ aio(0),
+ impl(cimpl->shared_from_this())
+{
+ QPID_LOG(debug, "TCPConnector created for " << version.toString());
+ settings.configureSocket(socket);
+}
+
+TCPConnector::~TCPConnector() {
+ close();
+}
+
+void TCPConnector::connect(const std::string& host, int port){
+ Mutex::ScopedLock l(closedLock);
+ assert(closed);
+ try {
+ socket.connect(host, port);
+ } catch (const std::exception& /*e*/) {
+ socket.close();
+ throw;
+ }
+
+ identifier = str(format("[%1% %2%]") % socket.getLocalPort() % socket.getPeerAddress());
+ closed = false;
+ poller = Poller::shared_ptr(new Poller);
+ aio = AsynchIO::create(socket,
+ boost::bind(&TCPConnector::readbuff, this, _1, _2),
+ boost::bind(&TCPConnector::eof, this, _1),
+ boost::bind(&TCPConnector::eof, this, _1),
+ 0, // closed
+ 0, // nobuffs
+ boost::bind(&TCPConnector::writebuff, this, _1));
+ writer.init(identifier, aio);
+}
+
+void TCPConnector::init(){
+ Mutex::ScopedLock l(closedLock);
+ assert(joined);
+ ProtocolInitiation init(version);
+ writeDataBlock(init);
+ joined = false;
+ receiver = Thread(this);
+}
+
+bool TCPConnector::closeInternal() {
+ Mutex::ScopedLock l(closedLock);
+ bool ret = !closed;
+ if (!closed) {
+ closed = true;
+ poller->shutdown();
+ }
+ if (!joined && receiver.id() != Thread::current().id()) {
+ joined = true;
+ Mutex::ScopedUnlock u(closedLock);
+ receiver.join();
+ }
+ return ret;
+}
+
+void TCPConnector::close() {
+ closeInternal();
+}
+
+void TCPConnector::setInputHandler(InputHandler* handler){
+ input = handler;
+}
+
+void TCPConnector::setShutdownHandler(ShutdownHandler* handler){
+ shutdownHandler = handler;
+}
+
+OutputHandler* TCPConnector::getOutputHandler() {
+ return this;
+}
+
+sys::ShutdownHandler* TCPConnector::getShutdownHandler() const {
+ return shutdownHandler;
+}
+
+const std::string& TCPConnector::getIdentifier() const {
+ return identifier;
+}
+
+void TCPConnector::send(AMQFrame& frame) {
+ writer.handle(frame);
+}
+
+void TCPConnector::handleClosed() {
+ if (closeInternal() && shutdownHandler)
+ shutdownHandler->shutdown();
+}
+
+struct TCPConnector::Buff : public AsynchIO::BufferBase {
+ Buff(size_t size) : AsynchIO::BufferBase(new char[size], size) {}
+ ~Buff() { delete [] bytes;}
+};
+
+TCPConnector::Writer::Writer(uint16_t s, Bounds* b) : maxFrameSize(s), aio(0), buffer(0), lastEof(0), bounds(b)
+{
+}
+
+TCPConnector::Writer::~Writer() { delete buffer; }
+
+void TCPConnector::Writer::init(std::string id, sys::AsynchIO* a) {
+ Mutex::ScopedLock l(lock);
+ identifier = id;
+ aio = a;
+ newBuffer();
+}
+void TCPConnector::Writer::handle(framing::AMQFrame& frame) {
+ Mutex::ScopedLock l(lock);
+ frames.push_back(frame);
+ //only try to write if this is the end of a frameset or if we
+ //already have a buffers worth of data
+ if (frame.getEof() || (bounds && bounds->getCurrentSize() >= maxFrameSize)) {
+ lastEof = frames.size();
+ aio->notifyPendingWrite();
+ }
+ QPID_LOG(trace, "SENT " << identifier << ": " << frame);
+}
+
+void TCPConnector::Writer::writeOne() {
+ assert(buffer);
+ framesEncoded = 0;
+
+ buffer->dataStart = 0;
+ buffer->dataCount = encode.getPosition();
+ aio->queueWrite(buffer);
+ newBuffer();
+}
+
+void TCPConnector::Writer::newBuffer() {
+ buffer = aio->getQueuedBuffer();
+ if (!buffer) buffer = new Buff(maxFrameSize);
+ encode = framing::Buffer(buffer->bytes, buffer->byteCount);
+ framesEncoded = 0;
+}
+
+// Called in IO thread.
+void TCPConnector::Writer::write(sys::AsynchIO&) {
+ Mutex::ScopedLock l(lock);
+ assert(buffer);
+ size_t bytesWritten(0);
+ for (size_t i = 0; i < lastEof; ++i) {
+ AMQFrame& frame = frames[i];
+ uint32_t size = frame.encodedSize();
+ if (size > encode.available()) writeOne();
+ assert(size <= encode.available());
+ frame.encode(encode);
+ ++framesEncoded;
+ bytesWritten += size;
+ }
+ frames.erase(frames.begin(), frames.begin()+lastEof);
+ lastEof = 0;
+ if (bounds) bounds->reduce(bytesWritten);
+ if (encode.getPosition() > 0) writeOne();
+}
+
+bool TCPConnector::readbuff(AsynchIO& aio, AsynchIO::BufferBase* buff) {
+ framing::Buffer in(buff->bytes+buff->dataStart, buff->dataCount);
+
+ if (!initiated) {
+ framing::ProtocolInitiation protocolInit;
+ if (protocolInit.decode(in)) {
+ //TODO: check the version is correct
+ QPID_LOG(debug, "RECV " << identifier << " INIT(" << protocolInit << ")");
+ }
+ initiated = true;
+ }
+ AMQFrame frame;
+ while(frame.decode(in)){
+ QPID_LOG(trace, "RECV " << identifier << ": " << frame);
+ input->received(frame);
+ }
+ // TODO: unreading needs to go away, and when we can cope
+ // with multiple sub-buffers in the general buffer scheme, it will
+ if (in.available() != 0) {
+ // Adjust buffer for used bytes and then "unread them"
+ buff->dataStart += buff->dataCount-in.available();
+ buff->dataCount = in.available();
+ aio.unread(buff);
+ } else {
+ // Give whole buffer back to aio subsystem
+ aio.queueReadBuffer(buff);
+ }
+ return true;
+}
+
+void TCPConnector::writebuff(AsynchIO& aio_) {
+ writer.write(aio_);
+}
+
+void TCPConnector::writeDataBlock(const AMQDataBlock& data) {
+ AsynchIO::BufferBase* buff = new Buff(maxFrameSize);
+ framing::Buffer out(buff->bytes, buff->byteCount);
+ data.encode(out);
+ buff->dataCount = data.encodedSize();
+ aio->queueWrite(buff);
+}
+
+void TCPConnector::eof(AsynchIO&) {
+ handleClosed();
+}
+
+// TODO: astitcher 20070908 This version of the code can never time out, so the idle processing
+// will never be called
+void TCPConnector::run(){
+ // Keep the connection impl in memory until run() completes.
+ boost::shared_ptr<ConnectionImpl> protect = impl.lock();
+ assert(protect);
+ try {
+ Dispatcher d(poller);
+
+ for (int i = 0; i < 32; i++) {
+ aio->queueReadBuffer(new Buff(maxFrameSize));
+ }
+
+ aio->start(poller);
+ d.run();
+ aio->queueForDeletion();
+ socket.close();
+ } catch (const std::exception& e) {
+ QPID_LOG(error, QPID_MSG("FAIL " << identifier << ": " << e.what()));
+ handleClosed();
+ }
+}
+
+
+}} // namespace qpid::client
diff --git a/RC9/qpid/cpp/src/qpid/client/Connector.h b/RC9/qpid/cpp/src/qpid/client/Connector.h
new file mode 100644
index 0000000000..5c37d95300
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/Connector.h
@@ -0,0 +1,73 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _Connector_
+#define _Connector_
+
+
+#include "qpid/framing/InputHandler.h"
+#include "qpid/framing/OutputHandler.h"
+#include "qpid/framing/InitiationHandler.h"
+#include "qpid/framing/ProtocolInitiation.h"
+#include "qpid/framing/ProtocolVersion.h"
+#include "qpid/sys/ShutdownHandler.h"
+#include "qpid/sys/TimeoutHandler.h"
+#include "qpid/sys/Thread.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Socket.h"
+#include "qpid/sys/Time.h"
+
+#include <queue>
+#include <boost/weak_ptr.hpp>
+#include <boost/shared_ptr.hpp>
+
+namespace qpid {
+namespace client {
+
+struct ConnectionSettings;
+class ConnectionImpl;
+
+///@internal
+class Connector : public framing::OutputHandler
+{
+ public:
+ // Protocol connector factory related stuff (it might be better to separate this code from the TCP Connector in the future)
+ typedef Connector* Factory(framing::ProtocolVersion, const ConnectionSettings&, ConnectionImpl*);
+ static Connector* create(const std::string& proto, framing::ProtocolVersion, const ConnectionSettings&, ConnectionImpl*);
+ static void registerFactory(const std::string& proto, Factory* connectorFactory);
+
+ virtual ~Connector() {};
+ virtual void connect(const std::string& host, int port) = 0;
+ virtual void init() {};
+ virtual void close() = 0;
+ virtual void send(framing::AMQFrame& frame) = 0;
+
+ virtual void setInputHandler(framing::InputHandler* handler) = 0;
+ virtual void setShutdownHandler(sys::ShutdownHandler* handler) = 0;
+ virtual sys::ShutdownHandler* getShutdownHandler() const = 0;
+ virtual framing::OutputHandler* getOutputHandler() = 0;
+ virtual const std::string& getIdentifier() const = 0;
+};
+
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/client/Demux.cpp b/RC9/qpid/cpp/src/qpid/client/Demux.cpp
new file mode 100644
index 0000000000..b774214ae4
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/Demux.cpp
@@ -0,0 +1,132 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Demux.h"
+#include "qpid/Exception.h"
+#include "qpid/framing/MessageTransferBody.h"
+
+#include <iostream>
+
+namespace qpid {
+namespace client {
+
+ByTransferDest::ByTransferDest(const std::string& d) : dest(d) {}
+bool ByTransferDest::operator()(const framing::FrameSet& frameset) const
+{
+ return frameset.isA<framing::MessageTransferBody>() &&
+ frameset.as<framing::MessageTransferBody>()->getDestination() == dest;
+}
+
+ScopedDivert::ScopedDivert(const std::string& _dest, Demux& _demuxer) : dest(_dest), demuxer(_demuxer)
+{
+ queue = demuxer.add(dest, ByTransferDest(dest));
+}
+
+ScopedDivert::~ScopedDivert()
+{
+ demuxer.remove(dest);
+}
+
+Demux::Demux() : defaultQueue(new Queue()) {}
+
+Demux::~Demux() { close(sys::ExceptionHolder(new ClosedException())); }
+
+Demux::QueuePtr ScopedDivert::getQueue()
+{
+ return queue;
+}
+
+void Demux::handle(framing::FrameSet::shared_ptr frameset)
+{
+ sys::Mutex::ScopedLock l(lock);
+ bool matched = false;
+ for (iterator i = records.begin(); i != records.end() && !matched; i++) {
+ if (i->condition && i->condition(*frameset)) {
+ matched = true;
+ i->queue->push(frameset);
+ }
+ }
+ if (!matched) {
+ defaultQueue->push(frameset);
+ }
+}
+
+void Demux::close(const sys::ExceptionHolder& ex)
+{
+ sys::Mutex::ScopedLock l(lock);
+ for (iterator i = records.begin(); i != records.end(); i++) {
+ i->queue->close(ex);
+ }
+ defaultQueue->close(ex);
+}
+
+void Demux::open()
+{
+ sys::Mutex::ScopedLock l(lock);
+ for (iterator i = records.begin(); i != records.end(); i++) {
+ i->queue->open();
+ }
+ defaultQueue->open();
+}
+
+Demux::QueuePtr Demux::add(const std::string& name, Condition condition)
+{
+ sys::Mutex::ScopedLock l(lock);
+ iterator i = std::find_if(records.begin(), records.end(), Find(name));
+ if (i == records.end()) {
+ Record r(name, condition);
+ records.push_back(r);
+ return r.queue;
+ } else {
+ throw Exception("Queue already exists for " + name);
+ }
+}
+
+void Demux::remove(const std::string& name)
+{
+ sys::Mutex::ScopedLock l(lock);
+ records.remove_if(Find(name));
+}
+
+Demux::QueuePtr Demux::get(const std::string& name)
+{
+ sys::Mutex::ScopedLock l(lock);
+ iterator i = std::find_if(records.begin(), records.end(), Find(name));
+ if (i == records.end()) {
+ throw Exception("No queue for " + name);
+ }
+ return i->queue;
+}
+
+Demux::QueuePtr Demux::getDefault()
+{
+ return defaultQueue;
+}
+
+Demux::Find::Find(const std::string& n) : name(n) {}
+
+bool Demux::Find::operator()(const Record& record) const
+{
+ return record.name == name;
+}
+
+}}
+
diff --git a/RC9/qpid/cpp/src/qpid/client/Demux.h b/RC9/qpid/cpp/src/qpid/client/Demux.h
new file mode 100644
index 0000000000..7304e799bb
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/Demux.h
@@ -0,0 +1,102 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <list>
+#include <boost/function.hpp>
+#include <boost/shared_ptr.hpp>
+#include "qpid/framing/FrameSet.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/BlockingQueue.h"
+
+#ifndef _Demux_
+#define _Demux_
+
+namespace qpid {
+namespace client {
+
+///@internal
+class ByTransferDest
+{
+ const std::string dest;
+public:
+ ByTransferDest(const std::string& dest);
+ bool operator()(const framing::FrameSet& frameset) const;
+};
+
+///@internal
+class Demux
+{
+public:
+ typedef boost::function<bool(const framing::FrameSet&)> Condition;
+ typedef sys::BlockingQueue<framing::FrameSet::shared_ptr> Queue;
+ typedef boost::shared_ptr<Queue> QueuePtr;
+
+ Demux();
+ ~Demux();
+
+ void handle(framing::FrameSet::shared_ptr);
+ void close(const sys::ExceptionHolder& ex);
+ void open();
+
+ QueuePtr add(const std::string& name, Condition);
+ void remove(const std::string& name);
+ QueuePtr get(const std::string& name);
+ QueuePtr getDefault();
+
+private:
+ struct Record
+ {
+ const std::string name;
+ Condition condition;
+ QueuePtr queue;
+
+ Record(const std::string& n, Condition c) : name(n), condition(c), queue(new Queue()) {}
+ };
+
+ sys::Mutex lock;
+ std::list<Record> records;
+ QueuePtr defaultQueue;
+
+ typedef std::list<Record>::iterator iterator;
+
+ struct Find
+ {
+ const std::string name;
+ Find(const std::string& name);
+ bool operator()(const Record& record) const;
+ };
+};
+
+class ScopedDivert
+{
+ const std::string dest;
+ Demux& demuxer;
+ Demux::QueuePtr queue;
+public:
+ ScopedDivert(const std::string& dest, Demux& demuxer);
+ ~ScopedDivert();
+ Demux::QueuePtr getQueue();
+};
+
+}} // namespace qpid::client
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/client/Dispatcher.cpp b/RC9/qpid/cpp/src/qpid/client/Dispatcher.cpp
new file mode 100644
index 0000000000..27cc4184f9
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/Dispatcher.cpp
@@ -0,0 +1,144 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "Dispatcher.h"
+#include "SubscriptionImpl.h"
+
+#include "qpid/framing/FrameSet.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/log/Statement.h"
+#include "qpid/sys/BlockingQueue.h"
+#include "Message.h"
+
+#include <boost/state_saver.hpp>
+
+using qpid::framing::FrameSet;
+using qpid::framing::MessageTransferBody;
+using qpid::sys::Mutex;
+using qpid::sys::ScopedLock;
+using qpid::sys::Thread;
+
+namespace qpid {
+namespace client {
+
+Dispatcher::Dispatcher(const Session& s, const std::string& q)
+ : session(s),
+ running(false),
+ autoStop(true),
+ failoverHandler(0)
+{
+ queue = q.empty() ?
+ session.getExecution().getDemux().getDefault() :
+ session.getExecution().getDemux().get(q);
+}
+
+void Dispatcher::start()
+{
+ worker = Thread(this);
+}
+
+void Dispatcher::wait()
+{
+ worker.join();
+}
+
+void Dispatcher::run()
+{
+ Mutex::ScopedLock l(lock);
+ if (running)
+ throw Exception("Dispatcher is already running.");
+ boost::state_saver<bool> reset(running); // Reset to false on exit.
+ running = true;
+ try {
+ while (!queue->isClosed()) {
+ Mutex::ScopedUnlock u(lock);
+ FrameSet::shared_ptr content = queue->pop();
+ if (content->isA<MessageTransferBody>()) {
+ Message msg(*content);
+ boost::intrusive_ptr<SubscriptionImpl> listener = find(msg.getDestination());
+ if (!listener) {
+ QPID_LOG(error, "No listener found for destination " << msg.getDestination());
+ } else {
+ assert(listener);
+ listener->received(msg);
+ }
+ } else {
+ if (handler.get()) {
+ handler->handle(*content);
+ } else {
+ QPID_LOG(warning, "No handler found for " << *(content->getMethod()));
+ }
+ }
+ }
+ session.sync(); // Make sure all our acks are received before returning.
+ }
+ catch (const ClosedException&) {
+ QPID_LOG(debug, QPID_MSG(session.getId() << ": closed by peer"));
+ }
+ catch (const TransportFailure&) {
+ QPID_LOG(info, QPID_MSG(session.getId() << ": transport failure"));
+ throw;
+ }
+ catch (const std::exception& e) {
+ if ( failoverHandler ) {
+ QPID_LOG(debug, QPID_MSG(session.getId() << " failover: " << e.what()));
+ failoverHandler();
+ } else {
+ QPID_LOG(error, session.getId() << " error: " << e.what());
+ throw;
+ }
+ }
+}
+
+void Dispatcher::stop()
+{
+ ScopedLock<Mutex> l(lock);
+ queue->close(); // Will interrupt thread blocked in pop()
+}
+
+void Dispatcher::setAutoStop(bool b)
+{
+ ScopedLock<Mutex> l(lock);
+ autoStop = b;
+}
+
+boost::intrusive_ptr<SubscriptionImpl> Dispatcher::find(const std::string& name)
+{
+ ScopedLock<Mutex> l(lock);
+ Listeners::iterator i = listeners.find(name);
+ if (i == listeners.end()) {
+ return defaultListener;
+ }
+ return i->second;
+}
+
+void Dispatcher::listen(const boost::intrusive_ptr<SubscriptionImpl>& subscription) {
+ ScopedLock<Mutex> l(lock);
+ listeners[subscription->getName()] = subscription;
+}
+
+void Dispatcher::cancel(const std::string& destination) {
+ ScopedLock<Mutex> l(lock);
+ listeners.erase(destination);
+ if (autoStop && listeners.empty())
+ queue->close();
+}
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/client/Dispatcher.h b/RC9/qpid/cpp/src/qpid/client/Dispatcher.h
new file mode 100644
index 0000000000..e84f8f303d
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/Dispatcher.h
@@ -0,0 +1,82 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _Dispatcher_
+#define _Dispatcher_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <boost/shared_ptr.hpp>
+#include "qpid/client/Session.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/sys/Thread.h"
+#include "MessageListener.h"
+#include "SubscriptionImpl.h"
+
+namespace qpid {
+namespace client {
+
+class SubscriptionImpl;
+
+///@internal
+typedef framing::Handler<framing::FrameSet> FrameSetHandler;
+
+///@internal
+class Dispatcher : public sys::Runnable
+{
+ typedef std::map<std::string, boost::intrusive_ptr<SubscriptionImpl> >Listeners;
+ sys::Mutex lock;
+ sys::Thread worker;
+ Session session;
+ Demux::QueuePtr queue;
+ bool running;
+ bool autoStop;
+ Listeners listeners;
+ boost::intrusive_ptr<SubscriptionImpl> defaultListener;
+ std::auto_ptr<FrameSetHandler> handler;
+
+ boost::intrusive_ptr<SubscriptionImpl> find(const std::string& name);
+ bool isStopped();
+
+ boost::function<void ()> failoverHandler;
+
+public:
+ Dispatcher(const Session& session, const std::string& queue = "");
+
+ void start();
+ void wait();
+ void run();
+ void stop();
+ void setAutoStop(bool b);
+
+ void registerFailoverHandler ( boost::function<void ()> fh )
+ {
+ failoverHandler = fh;
+ }
+
+ void listen(const boost::intrusive_ptr<SubscriptionImpl>& subscription);
+ void cancel(const std::string& destination);
+};
+
+}}
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/client/Execution.h b/RC9/qpid/cpp/src/qpid/client/Execution.h
new file mode 100644
index 0000000000..10674afde0
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/Execution.h
@@ -0,0 +1,53 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _Execution_
+#define _Execution_
+
+#include "qpid/framing/SequenceNumber.h"
+#include "Demux.h"
+
+namespace qpid {
+namespace client {
+
+/**@internal
+ *
+ * Provides access to more detailed aspects of the session
+ * implementation.
+ */
+class Execution
+{
+public:
+ virtual ~Execution() {}
+ /**
+ * Provides access to the demultiplexing function within the
+ * session implementation
+ */
+ virtual Demux& getDemux() = 0;
+ /**
+ * Wait until notification has been received of completion of the
+ * outgoing command with the specified id.
+ */
+ void waitForCompletion(const framing::SequenceNumber& id);
+};
+
+}}
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/client/FailoverListener.cpp b/RC9/qpid/cpp/src/qpid/client/FailoverListener.cpp
new file mode 100644
index 0000000000..16370f8912
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/FailoverListener.cpp
@@ -0,0 +1,115 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "FailoverListener.h"
+#include "SessionBase_0_10Access.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/log/Statement.h"
+#include "qpid/log/Helpers.h"
+
+namespace qpid {
+namespace client {
+
+static const std::string AMQ_FAILOVER("amq.failover");
+
+static Session makeSession(boost::shared_ptr<SessionImpl> si) {
+ // Hold only a weak pointer to the ConnectionImpl so a
+ // FailoverListener in a ConnectionImpl won't createa a shared_ptr
+ // cycle.
+ //
+ si->setWeakPtr(true);
+ Session s;
+ SessionBase_0_10Access(s).set(si);
+ return s;
+}
+
+FailoverListener::FailoverListener(const boost::shared_ptr<ConnectionImpl>& c, const std::vector<Url>& initUrls)
+ : knownBrokers(initUrls)
+ {
+ // Special versions used to mark cluster catch-up connections
+ // which do not need a FailoverListener
+ if (c->getVersion().getMajor() >= 0x80) {
+ QPID_LOG(debug, "No failover listener for catch-up connection.");
+ return;
+ }
+
+ Session session = makeSession(c->newSession(AMQ_FAILOVER+framing::Uuid(true).str(), 0));
+ if (session.exchangeQuery(arg::name=AMQ_FAILOVER).getNotFound()) {
+ session.close();
+ return;
+ }
+ subscriptions.reset(new SubscriptionManager(session));
+ std::string qname=session.getId().getName();
+ session.queueDeclare(arg::queue=qname, arg::exclusive=true, arg::autoDelete=true);
+ session.exchangeBind(arg::queue=qname, arg::exchange=AMQ_FAILOVER);
+ subscriptions->subscribe(*this, qname, SubscriptionSettings(FlowControl::unlimited(), ACCEPT_MODE_NONE));
+ thread = sys::Thread(*this);
+}
+
+void FailoverListener::run()
+{
+ try {
+ subscriptions->run();
+ } catch (const TransportFailure&) {
+ } catch (const std::exception& e) {
+ QPID_LOG(error, QPID_MSG(e.what()));
+ }
+}
+
+FailoverListener::~FailoverListener() {
+ try { stop(); }
+ catch (const std::exception& /*e*/) {}
+}
+
+void FailoverListener::stop() {
+ if (subscriptions.get())
+ subscriptions->stop();
+
+ if (thread.id() == sys::Thread::current().id()) {
+ // FIXME aconway 2008-10-16: this can happen if ConnectionImpl
+ // dtor runs when my session drops its weak pointer lock.
+ // For now, leak subscriptions to prevent a core if we delete
+ // without joining.
+ subscriptions.release();
+ }
+ else if (thread.id()) {
+ thread.join();
+ thread=sys::Thread();
+ subscriptions.reset(); // Safe to delete after join.
+ }
+}
+
+void FailoverListener::received(Message& msg) {
+ sys::Mutex::ScopedLock l(lock);
+ knownBrokers.clear();
+ framing::Array urlArray;
+ msg.getHeaders().getArray("amq.failover", urlArray);
+ for (framing::Array::ValueVector::const_iterator i = urlArray.begin(); i != urlArray.end(); ++i )
+ knownBrokers.push_back(Url((*i)->get<std::string>()));
+ QPID_LOG(info, "Known-brokers update: " << log::formatList(knownBrokers));
+}
+
+std::vector<Url> FailoverListener::getKnownBrokers() const {
+ sys::Mutex::ScopedLock l(lock);
+ return knownBrokers;
+}
+
+}} // namespace qpid::client
diff --git a/RC9/qpid/cpp/src/qpid/client/FailoverListener.h b/RC9/qpid/cpp/src/qpid/client/FailoverListener.h
new file mode 100644
index 0000000000..fe73a26611
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/FailoverListener.h
@@ -0,0 +1,59 @@
+#ifndef QPID_CLIENT_FAILOVERLISTENER_H
+#define QPID_CLIENT_FAILOVERLISTENER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/client/MessageListener.h"
+#include "qpid/Url.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/sys/Thread.h"
+#include <vector>
+
+namespace qpid {
+namespace client {
+
+class SubscriptionManager;
+
+/**
+ * @internal Listen for failover updates from the amq.failover exchange.
+ */
+class FailoverListener : public MessageListener, private qpid::sys::Runnable
+{
+ public:
+ FailoverListener(const boost::shared_ptr<ConnectionImpl>&, const std::vector<Url>& initUrls);
+ ~FailoverListener();
+ void stop();
+
+ std::vector<Url> getKnownBrokers() const;
+ void received(Message& msg);
+ void run();
+
+ private:
+ mutable sys::Mutex lock;
+ std::auto_ptr<SubscriptionManager> subscriptions;
+ sys::Thread thread;
+ std::vector<Url> knownBrokers;
+};
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_FAILOVERLISTENER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/client/FailoverManager.cpp b/RC9/qpid/cpp/src/qpid/client/FailoverManager.cpp
new file mode 100644
index 0000000000..ab9dbca70f
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/FailoverManager.cpp
@@ -0,0 +1,119 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "FailoverManager.h"
+#include "qpid/Exception.h"
+#include "qpid/log/Statement.h"
+
+
+namespace qpid {
+namespace client {
+
+using qpid::sys::Monitor;
+
+FailoverManager::FailoverManager(const ConnectionSettings& s,
+ ReconnectionStrategy* rs) : settings(s), strategy(rs), state(IDLE) {}
+
+void FailoverManager::execute(Command& c)
+{
+ bool retry = false;
+ bool completed = false;
+ while (!completed) {
+ try {
+ AsyncSession session = connect().newSession();
+ c.execute(session, retry);
+ session.sync();//TODO: shouldn't be required
+ session.close();
+ completed = true;
+ } catch(const TransportFailure&) {
+ retry = true;
+ }
+ }
+}
+
+void FailoverManager::close()
+{
+ Monitor::ScopedLock l(lock);
+ connection.close();
+}
+
+Connection& FailoverManager::connect(std::vector<Url> brokers)
+{
+ Monitor::ScopedLock l(lock);
+ if (state == CANT_CONNECT) {
+ state = IDLE;//retry
+ }
+ while (!connection.isOpen()) {
+ if (state == CONNECTING) {
+ lock.wait();
+ } else if (state == CANT_CONNECT) {
+ throw CannotConnectException("Cannot establish a connection");
+ } else {
+ state = CONNECTING;
+ Connection c;
+ attempt(c, settings, brokers.empty() ? connection.getKnownBrokers() : brokers);
+ if (c.isOpen()) state = IDLE;
+ else state = CANT_CONNECT;
+ connection = c;
+ lock.notifyAll();
+ }
+ }
+ return connection;
+}
+
+Connection& FailoverManager::getConnection()
+{
+ Monitor::ScopedLock l(lock);
+ return connection;
+}
+
+void FailoverManager::attempt(Connection& c, ConnectionSettings s, std::vector<Url> urls)
+{
+ Monitor::ScopedUnlock u(lock);
+ if (strategy) strategy->editUrlList(urls);
+ if (urls.empty()) {
+ attempt(c, s);
+ } else {
+ for (std::vector<Url>::const_iterator i = urls.begin(); i != urls.end() && !c.isOpen(); ++i) {
+ for (Url::const_iterator j = i->begin(); j != i->end() && !c.isOpen(); ++j) {
+ const TcpAddress* tcp = j->get<TcpAddress>();
+ if (tcp) {
+ s.host = tcp->host;
+ s.port = tcp->port;
+ attempt(c, s);
+ }
+ }
+ }
+ }
+}
+
+void FailoverManager::attempt(Connection& c, ConnectionSettings s)
+{
+ try {
+ QPID_LOG(info, "Attempting to connect to " << s.host << " on " << s.port << "...");
+ c.open(s);
+ QPID_LOG(info, "Connected to " << s.host << " on " << s.port);
+ } catch (const Exception& e) {
+ QPID_LOG(info, "Could not connect to " << s.host << " on " << s.port << ": " << e.what());
+ }
+}
+
+
+}} // namespace qpid::client
diff --git a/RC9/qpid/cpp/src/qpid/client/FailoverManager.h b/RC9/qpid/cpp/src/qpid/client/FailoverManager.h
new file mode 100644
index 0000000000..8b6eeda8a1
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/FailoverManager.h
@@ -0,0 +1,134 @@
+#ifndef QPID_CLIENT_FAILOVERMANAGER_H
+#define QPID_CLIENT_FAILOVERMANAGER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Connection.h"
+#include "ConnectionSettings.h"
+#include "qpid/Exception.h"
+#include "qpid/client/AsyncSession.h"
+#include "qpid/sys/Monitor.h"
+#include <vector>
+
+namespace qpid {
+namespace client {
+
+struct CannotConnectException : qpid::Exception
+{
+ CannotConnectException(const std::string& m) : qpid::Exception(m) {}
+};
+
+/**
+ * Utility to manage failover.
+ */
+class FailoverManager
+{
+ public:
+ /**
+ * Interface to implement for doing work that can be resumed on
+ * failover
+ */
+ struct Command
+ {
+ /**
+ * This method will be called with isRetry=false when the
+ * command is first executed. The session to use for the work
+ * will be passed to the implementing class. If the connection
+ * fails while the execute call is in progress, the
+ * FailoverManager controlling the execution will re-establish
+ * a connection, open a new session and call back to the
+ * Command implementations execute method with the new session
+ * and isRetry=true.
+ */
+ virtual void execute(AsyncSession& session, bool isRetry) = 0;
+ virtual ~Command() {}
+ };
+
+ struct ReconnectionStrategy
+ {
+ /**
+ * This method is called by the FailoverManager prior to
+ * establishing a connection (or re-connection) and can be
+ * used if the application wishes to edit or re-order the list
+ * which will default to the list of known brokers for the
+ * last connection.
+ */
+ virtual void editUrlList(std::vector<Url>& urls) = 0;
+ virtual ~ReconnectionStrategy() {}
+ };
+
+ /**
+ * Create a manager to control failover for a logical connection.
+ *
+ * @param settings the initial connection settings
+ * @param strategy optional stratgey callback allowing application
+ * to edit or reorder the list of urls to which reconnection is
+ * attempted
+ */
+ FailoverManager(const ConnectionSettings& settings, ReconnectionStrategy* strategy = 0);
+ /**
+ * Return the current connection if open or attept to reconnect to
+ * the specified list of urls. If no list is specified the list of
+ * known brokers from the last connection will be used. If no list
+ * is specified and this is the first connect attempt, the host
+ * and port from the initial settings will be used.
+ *
+ * If the full list is tried and all attempts fail,
+ * CannotConnectException is thrown.
+ */
+ Connection& connect(std::vector<Url> brokers = std::vector<Url>());
+ /**
+ * Return the current connection whether open or not
+ */
+ Connection& getConnection();
+ /**
+ * Close the current connection
+ */
+ void close();
+ /**
+ * Reliably execute the specified command. This involves creating
+ * a session on which to carry out the work of the command,
+ * handling failover occuring while exeuting that command and
+ * re-starting the work.
+ *
+ * Multiple concurrent threads can call execute with different
+ * commands; each thread will be allocated its own
+ * session. FailoverManager will coordinate the different threads
+ * on failover to ensure they continue to use the same logical
+ * connection.
+ */
+ void execute(Command&);
+ private:
+ enum State {IDLE, CONNECTING, CANT_CONNECT};
+
+ qpid::sys::Monitor lock;
+ Connection connection;
+ ConnectionSettings settings;
+ ReconnectionStrategy* strategy;
+ State state;
+
+ void attempt(Connection&, ConnectionSettings settings, std::vector<Url> urls);
+ void attempt(Connection&, ConnectionSettings settings);
+};
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_FAILOVERMANAGER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/client/FlowControl.h b/RC9/qpid/cpp/src/qpid/client/FlowControl.h
new file mode 100644
index 0000000000..d2205aaa78
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/FlowControl.h
@@ -0,0 +1,75 @@
+#ifndef QPID_CLIENT_FLOWCONTROL_H
+#define QPID_CLIENT_FLOWCONTROL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/sys/IntegerTypes.h>
+
+namespace qpid {
+namespace client {
+
+/**
+ * Flow control works by associating a finite amount of "credit"
+ * with a subscription.
+ *
+ * Credit includes a message count and a byte count. Each message
+ * received decreases the message count by one, and the byte count by
+ * the size of the message. Either count can have the special value
+ * UNLIMITED which is never decreased.
+ *
+ * A subscription's credit is exhausted when the message count is 0 or
+ * the byte count is too small for the next available message. The
+ * subscription will not receive any further messages until is credit
+ * is renewed.
+ *
+ * In "window mode" credit is automatically renewed when a message is
+ * completed (which by default happens when it is accepted). In
+ * non-window mode credit is not automatically renewed, it must be
+ * explicitly re-set (@see Subscription)
+ */
+struct FlowControl {
+ static const uint32_t UNLIMITED=0xFFFFFFFF;
+ FlowControl(uint32_t messages_=0, uint32_t bytes_=0, bool window_=false)
+ : messages(messages_), bytes(bytes_), window(window_) {}
+
+ static FlowControl messageCredit(uint32_t messages_) { return FlowControl(messages_,UNLIMITED,false); }
+ static FlowControl messageWindow(uint32_t messages_) { return FlowControl(messages_,UNLIMITED,true); }
+ static FlowControl byteCredit(uint32_t bytes_) { return FlowControl(UNLIMITED,bytes_,false); }
+ static FlowControl byteWindow(uint32_t bytes_) { return FlowControl(UNLIMITED,bytes_,true); }
+ static FlowControl unlimited() { return FlowControl(UNLIMITED, UNLIMITED, false); }
+ static FlowControl zero() { return FlowControl(0, 0, false); }
+
+ /** Message credit: subscription can accept up to this many messages. */
+ uint32_t messages;
+ /** Byte credit: subscription can accept up to this many bytes of message content. */
+ uint32_t bytes;
+ /** Window mode. If true credit is automatically renewed as messages are acknowledged. */
+ bool window;
+
+ bool operator==(const FlowControl& x) {
+ return messages == x.messages && bytes == x.bytes && window == x.window;
+ };
+};
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_FLOWCONTROL_H*/
diff --git a/RC9/qpid/cpp/src/qpid/client/Future.cpp b/RC9/qpid/cpp/src/qpid/client/Future.cpp
new file mode 100644
index 0000000000..6a0c78ae4b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/Future.cpp
@@ -0,0 +1,45 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Future.h"
+
+namespace qpid {
+namespace client {
+
+void Future::wait(SessionImpl& session)
+{
+ if (!complete) {
+ session.waitForCompletion(command);
+ }
+ complete = true;
+}
+
+bool Future::isComplete(SessionImpl& session)
+{
+ return complete || session.isComplete(command);
+}
+
+void Future::setFutureResult(boost::shared_ptr<FutureResult> r)
+{
+ result = r;
+}
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/client/Future.h b/RC9/qpid/cpp/src/qpid/client/Future.h
new file mode 100644
index 0000000000..67f39cdf3f
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/Future.h
@@ -0,0 +1,64 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef _Future_
+#define _Future_
+
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include "qpid/Exception.h"
+#include "qpid/framing/SequenceNumber.h"
+#include "qpid/framing/StructHelper.h"
+#include "FutureCompletion.h"
+#include "FutureResult.h"
+#include "SessionImpl.h"
+
+namespace qpid {
+namespace client {
+
+/**@internal */
+class Future : private framing::StructHelper
+{
+ framing::SequenceNumber command;
+ boost::shared_ptr<FutureResult> result;
+ bool complete;
+
+public:
+ Future() : complete(false) {}
+ Future(const framing::SequenceNumber& id) : command(id), complete(false) {}
+
+ template <class T> void decodeResult(T& value, SessionImpl& session)
+ {
+ if (result) {
+ decode(value, result->getResult(session));
+ } else {
+ throw Exception("Result not expected");
+ }
+ }
+
+ void wait(SessionImpl& session);
+ bool isComplete(SessionImpl& session);
+ void setFutureResult(boost::shared_ptr<FutureResult> r);
+};
+
+}}
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/client/FutureCompletion.cpp b/RC9/qpid/cpp/src/qpid/client/FutureCompletion.cpp
new file mode 100644
index 0000000000..130c65d6aa
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/FutureCompletion.cpp
@@ -0,0 +1,48 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "FutureCompletion.h"
+
+using namespace qpid::client;
+using namespace qpid::sys;
+
+FutureCompletion::FutureCompletion() : complete(false) {}
+
+bool FutureCompletion::isComplete() const
+{
+ Monitor::ScopedLock l(lock);
+ return complete;
+}
+
+void FutureCompletion::completed()
+{
+ Monitor::ScopedLock l(lock);
+ complete = true;
+ lock.notifyAll();
+}
+
+void FutureCompletion::waitForCompletion() const
+{
+ Monitor::ScopedLock l(lock);
+ while (!complete) {
+ lock.wait();
+ }
+}
diff --git a/RC9/qpid/cpp/src/qpid/client/FutureCompletion.h b/RC9/qpid/cpp/src/qpid/client/FutureCompletion.h
new file mode 100644
index 0000000000..4248ddeab8
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/FutureCompletion.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef _FutureCompletion_
+#define _FutureCompletion_
+
+#include "qpid/framing/amqp_framing.h"
+#include "qpid/sys/Monitor.h"
+
+namespace qpid {
+namespace client {
+
+///@internal
+class FutureCompletion
+{
+protected:
+ mutable sys::Monitor lock;
+ bool complete;
+
+public:
+ FutureCompletion();
+ virtual ~FutureCompletion(){}
+ bool isComplete() const;
+ void waitForCompletion() const;
+ void completed();
+};
+
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/client/FutureResult.cpp b/RC9/qpid/cpp/src/qpid/client/FutureResult.cpp
new file mode 100644
index 0000000000..007f278051
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/FutureResult.cpp
@@ -0,0 +1,43 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "FutureResult.h"
+
+#include "SessionImpl.h"
+
+using namespace qpid::client;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+const std::string& FutureResult::getResult(SessionImpl& session) const
+{
+ waitForCompletion();
+ session.assertOpen();
+ return result;
+}
+
+void FutureResult::received(const std::string& r)
+{
+ Monitor::ScopedLock l(lock);
+ result = r;
+ complete = true;
+ lock.notifyAll();
+}
diff --git a/RC9/qpid/cpp/src/qpid/client/FutureResult.h b/RC9/qpid/cpp/src/qpid/client/FutureResult.h
new file mode 100644
index 0000000000..e97d80476d
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/FutureResult.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef _FutureResult_
+#define _FutureResult_
+
+#include <string>
+#include "qpid/framing/amqp_framing.h"
+#include "FutureCompletion.h"
+
+namespace qpid {
+namespace client {
+
+class SessionImpl;
+
+///@internal
+class FutureResult : public FutureCompletion
+{
+ std::string result;
+public:
+ const std::string& getResult(SessionImpl& session) const;
+ void received(const std::string& result);
+};
+
+}}
+
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/client/Handle.h b/RC9/qpid/cpp/src/qpid/client/Handle.h
new file mode 100644
index 0000000000..4fd82b7646
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/Handle.h
@@ -0,0 +1,61 @@
+#ifndef QPID_CLIENT_HANDLE_H
+#define QPID_CLIENT_HANDLE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+namespace qpid {
+namespace client {
+
+template <class T> class HandlePrivate;
+
+/**
+ * A handle is like a pointer: it points to some underlying object.
+ * Handles can be null, like a 0 pointer. Use isValid(), isNull() or the
+ * implicit conversion to bool to test for a null handle.
+ */
+template <class T> class Handle {
+ public:
+ ~Handle();
+ Handle(const Handle&);
+ Handle& operator=(const Handle&);
+
+ /**@return true if handle is valid, i.e. not null. */
+ bool isValid() const { return impl; }
+
+ /**@return true if handle is null. It is an error to call any function on a null handle. */
+ bool isNull() const { return !impl; }
+
+ operator bool() const { return impl; }
+ bool operator !() const { return impl; }
+
+ void swap(Handle<T>&);
+
+ protected:
+ Handle(T* =0);
+ T* impl;
+
+ friend class HandlePrivate<T>;
+};
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_HANDLE_H*/
diff --git a/RC9/qpid/cpp/src/qpid/client/HandleAccess.h b/RC9/qpid/cpp/src/qpid/client/HandleAccess.h
new file mode 100644
index 0000000000..f1747db638
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/HandleAccess.h
@@ -0,0 +1,41 @@
+#ifndef QPID_CLIENT_HANDLEACCESS_H
+#define QPID_CLIENT_HANDLEACCESS_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <Handle.h>
+
+namespace qpid {
+namespace client {
+
+/**
+ * Provide access to the private impl member of a Handle.
+ */
+template <class T>
+class HandleAccess
+{
+ public:
+ static boost::shared_ptr<T> getImpl(Handle<T>& h) { return h.impl; }
+};
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_HANDLEACCESS_H*/
diff --git a/RC9/qpid/cpp/src/qpid/client/HandlePrivate.h b/RC9/qpid/cpp/src/qpid/client/HandlePrivate.h
new file mode 100644
index 0000000000..488ce48075
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/HandlePrivate.h
@@ -0,0 +1,61 @@
+#ifndef QPID_CLIENT_HANDLEPRIVATE_H
+#define QPID_CLIENT_HANDLEPRIVATE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <algorithm>
+
+namespace qpid {
+namespace client {
+
+/** @file
+ * Private implementation of handle, include in .cpp file of handle
+ * subclasses _after_ including the declaration of class T.
+ * T can be any class that can be used with boost::intrusive_ptr.
+ */
+
+template <class T>
+Handle<T>::Handle(T* p) : impl(p) { if (impl) boost::intrusive_ptr_add_ref(impl); }
+
+template <class T>
+Handle<T>::~Handle() { if(impl) boost::intrusive_ptr_release(impl); }
+
+template <class T>
+Handle<T>::Handle(const Handle& h) : impl(h.impl) { if(impl) boost::intrusive_ptr_add_ref(impl); }
+
+template <class T>
+Handle<T>& Handle<T>::operator=(const Handle<T>& h) { Handle<T>(h).swap(*this); return *this; }
+
+template <class T>
+void Handle<T>::swap(Handle<T>& h) { std::swap(impl, h.impl); }
+
+
+/** Access to private impl of a Handle */
+template <class T>
+class HandlePrivate {
+ public:
+ static boost::intrusive_ptr<T> get(Handle<T>& h) { return boost::intrusive_ptr<T>(h.impl); }
+};
+
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_HANDLEPRIVATE_H*/
diff --git a/RC9/qpid/cpp/src/qpid/client/LoadPlugins.cpp b/RC9/qpid/cpp/src/qpid/client/LoadPlugins.cpp
new file mode 100644
index 0000000000..b395226859
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/LoadPlugins.cpp
@@ -0,0 +1,49 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/Modules.h"
+#include "qpid/sys/Shlib.h"
+#include <string>
+#include <vector>
+using std::vector;
+using std::string;
+
+namespace {
+
+struct LoadtimeInitialise {
+ LoadtimeInitialise() {
+ qpid::ModuleOptions moduleOptions(MODULE_DIR);
+ string defaultPath (moduleOptions.loadDir);
+ moduleOptions.parse (0, 0, CONF_FILE, true);
+
+ for (vector<string>::iterator iter = moduleOptions.load.begin();
+ iter != moduleOptions.load.end();
+ iter++)
+ qpid::tryShlib (iter->data(), false);
+
+ if (!moduleOptions.noLoad) {
+ bool isDefault = defaultPath == moduleOptions.loadDir;
+ qpid::loadModuleDir (moduleOptions.loadDir, isDefault);
+ }
+ }
+} init;
+
+} // namespace
diff --git a/RC9/qpid/cpp/src/qpid/client/LocalQueue.cpp b/RC9/qpid/cpp/src/qpid/client/LocalQueue.cpp
new file mode 100644
index 0000000000..e449c9f795
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/LocalQueue.cpp
@@ -0,0 +1,77 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "LocalQueue.h"
+#include "qpid/Exception.h"
+#include "qpid/framing/FrameSet.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "HandlePrivate.h"
+#include "SubscriptionImpl.h"
+
+namespace qpid {
+namespace client {
+
+using namespace framing;
+
+LocalQueue::LocalQueue() {}
+LocalQueue::~LocalQueue() {}
+
+Message LocalQueue::pop(sys::Duration timeout) { return get(timeout); }
+
+Message LocalQueue::get(sys::Duration timeout) {
+ Message result;
+ bool ok = get(result, timeout);
+ if (!ok) throw Exception("Timed out waiting for a message");
+ return result;
+}
+
+bool LocalQueue::get(Message& result, sys::Duration timeout) {
+ if (!queue)
+ throw ClosedException();
+ FrameSet::shared_ptr content;
+ bool ok = queue->pop(content, timeout);
+ if (!ok) return false;
+ if (content->isA<MessageTransferBody>()) {
+ result = Message(*content);
+ boost::intrusive_ptr<SubscriptionImpl> si = HandlePrivate<SubscriptionImpl>::get(subscription);
+ assert(si);
+ if (si) si->received(result);
+ return true;
+ }
+ else
+ throw CommandInvalidException(
+ QPID_MSG("Unexpected method: " << content->getMethod()));
+}
+
+bool LocalQueue::empty() const
+{
+ if (!queue)
+ throw ClosedException();
+ return queue->empty();
+}
+
+size_t LocalQueue::size() const
+{
+ if (!queue)
+ throw ClosedException();
+ return queue->size();
+}
+
+}} // namespace qpid::client
diff --git a/RC9/qpid/cpp/src/qpid/client/LocalQueue.h b/RC9/qpid/cpp/src/qpid/client/LocalQueue.h
new file mode 100644
index 0000000000..30ea00612d
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/LocalQueue.h
@@ -0,0 +1,115 @@
+#ifndef QPID_CLIENT_LOCALQUEUE_H
+#define QPID_CLIENT_LOCALQUEUE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/client/Message.h"
+#include "qpid/client/Subscription.h"
+#include "qpid/client/Demux.h"
+#include "qpid/sys/Time.h"
+
+namespace qpid {
+namespace client {
+
+/**
+ * A local queue to collect messages retrieved from a remote broker
+ * queue. Create a queue and subscribe it using the SubscriptionManager.
+ * Messages from the remote queue on the broker will be stored in the
+ * local queue until you retrieve them.
+ *
+ * \ingroup clientapi
+ *
+ * \details Using a Local Queue
+ *
+ * <pre>
+ * LocalQueue local_queue;
+ * subscriptions.subscribe(local_queue, string("message_queue"));
+ * for (int i=0; i&lt;10; i++) {
+ * Message message = local_queue.get();
+ * std::cout &lt;&lt; message.getData() &lt;&lt; std::endl;
+ * }
+ * </pre>
+ *
+ * <h2>Getting Messages</h2>
+ *
+ * <ul><li>
+ * <p>get()</p>
+ * <pre>Message message = local_queue.get();</pre>
+ * <pre>// Specifying timeouts (TIME_SEC, TIME_MSEC, TIME_USEC, TIME_NSEC)
+ *#include <qpid/sys/Time.h>
+ *Message message;
+ *local_queue.get(message, 5*sys::TIME_SEC);</pre></li></ul>
+ *
+ * <h2>Checking size</h2>
+ * <ul><li>
+ * <p>empty()</p>
+ * <pre>if (local_queue.empty()) { ... }</pre></li>
+ * <li><p>size()</p>
+ * <pre>std::cout &lt;&lt; local_queue.size();</pre></li>
+ * </ul>
+ */
+
+class LocalQueue {
+ public:
+ /** Create a local queue. Subscribe the local queue to a remote broker
+ * queue with a SubscriptionManager.
+ *
+ * LocalQueue is an alternative to implementing a MessageListener.
+ */
+ LocalQueue();
+
+ ~LocalQueue();
+
+ /** Wait up to timeout for the next message from the local queue.
+ *@param result Set to the message from the queue.
+ *@param timeout wait up this timeout for a message to appear.
+ *@return true if result was set, false if queue was empty after timeout.
+ */
+ bool get(Message& result, sys::Duration timeout=0);
+
+ /** Get the next message off the local queue, or wait up to the timeout
+ * for message from the broker queue.
+ *@param timeout wait up this timeout for a message to appear.
+ *@return message from the queue.
+ *@throw ClosedException if subscription is closed or timeout exceeded.
+ */
+ Message get(sys::Duration timeout=sys::TIME_INFINITE);
+
+ /** Synonym for get() */
+ Message pop(sys::Duration timeout=sys::TIME_INFINITE);
+
+ /** Return true if local queue is empty. */
+ bool empty() const;
+
+ /** Number of messages on the local queue */
+ size_t size() const;
+
+ private:
+ Demux::QueuePtr queue;
+ Subscription subscription;
+
+ friend class SubscriptionManager;
+};
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_LOCALQUEUE_H*/
diff --git a/RC9/qpid/cpp/src/qpid/client/Message.cpp b/RC9/qpid/cpp/src/qpid/client/Message.cpp
new file mode 100644
index 0000000000..13caaecefd
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/Message.cpp
@@ -0,0 +1,71 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Message.h"
+
+namespace qpid {
+namespace client {
+
+Message::Message(const std::string& data, const std::string& routingKey) : TransferContent(data, routingKey) {}
+
+std::string Message::getDestination() const
+{
+ return method.getDestination();
+}
+
+bool Message::isRedelivered() const
+{
+ return hasDeliveryProperties() && getDeliveryProperties().getRedelivered();
+}
+
+void Message::setRedelivered(bool redelivered)
+{
+ getDeliveryProperties().setRedelivered(redelivered);
+}
+
+framing::FieldTable& Message::getHeaders()
+{
+ return getMessageProperties().getApplicationHeaders();
+}
+
+const framing::FieldTable& Message::getHeaders() const
+{
+ return getMessageProperties().getApplicationHeaders();
+}
+
+const framing::MessageTransferBody& Message::getMethod() const
+{
+ return method;
+}
+
+const framing::SequenceNumber& Message::getId() const
+{
+ return id;
+}
+
+/**@internal for incoming messages */
+Message::Message(const framing::FrameSet& frameset) :
+ method(*frameset.as<framing::MessageTransferBody>()), id(frameset.getId())
+{
+ populate(frameset);
+}
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/client/Message.h b/RC9/qpid/cpp/src/qpid/client/Message.h
new file mode 100644
index 0000000000..3f932efd8b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/Message.h
@@ -0,0 +1,151 @@
+#ifndef _client_Message_h
+#define _client_Message_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <string>
+#include "qpid/client/Session.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/framing/TransferContent.h"
+
+namespace qpid {
+namespace client {
+
+/**
+ * A message sent to or received from the broker.
+ *
+ * \ingroup clientapi
+ * \details
+ *
+ * <h2>Getting and setting message contents</h2>
+ *
+ * <ul>
+ * <li>
+ * <p>getData()</p>
+ * <pre>std::cout &lt;&lt; "Response: " &lt;&lt; message.getData() &lt;&lt; std::endl;</pre>
+ * </li>
+ * <li>
+ * <p>setData()</p>
+ * <pre>message.setData("That's all, folks!");</pre></li>
+ * <li>
+ * <p>appendData()</p>
+ * <pre>message.appendData(" ... let's add a bit more ...");</pre></li>
+ * </ul>
+ *
+ * <h2>Getting and Setting Delivery Properties</h2>
+ *
+ * <ul>
+ * <li>
+ * <p>getDeliveryProperties()</p>
+ * <pre>message.getDeliveryProperties().setRoutingKey("control");</pre>
+ * <pre>message.getDeliveryProperties().setDeliveryMode(PERSISTENT);</pre>
+ * <pre>message.getDeliveryProperties().setPriority(9);</pre>
+ * <pre>message.getDeliveryProperties().setTtl(100);</pre></li>
+ *
+ * <li>
+ * <p>hasDeliveryProperties()</p>
+ * <pre>if (! message.hasDeliveryProperties()) {
+ * ...
+ *}</pre></li>
+ * </ul>
+ *
+ * <h2>Getting and Setting Message Properties</h2>
+ *
+ * <ul>
+ * <li>
+ * <p>getMessageProperties()</p>
+ * <pre>
+ *request.getMessageProperties().setReplyTo(ReplyTo("amq.direct", response_queue.str()));
+ * </pre>
+ * <pre>
+ *routingKey = request.getMessageProperties().getReplyTo().getRoutingKey();
+ *exchange = request.getMessageProperties().getReplyTo().getExchange();
+ * </pre>
+ * <pre>message.getMessageProperties().setContentType("text/plain");</pre>
+ * <pre>message.getMessageProperties().setContentEncoding("text/plain");</pre>
+ * </li>
+ * <li>
+ * <p>hasMessageProperties()</p>
+ * <pre>request.getMessageProperties().hasReplyTo();</pre>
+ * </li>
+ * </ul>
+ *
+ * <h2>Getting and Setting Application Headers</h2>
+ *
+ * <ul>
+ * <li>
+ * <p>getHeaders()</p>
+ * <pre>
+ *message.getHeaders().getString("control");
+ * </pre>
+ * <pre>
+ *message.getHeaders().setString("control","continue");
+ * </pre></li>
+ * </ul>
+ *
+ *
+ */
+
+class Message : public framing::TransferContent
+{
+public:
+ /** Create a Message.
+ *@param data Data for the message body.
+ *@param routingKey Passed to the exchange that routes the message.
+ */
+ Message(const std::string& data=std::string(),
+ const std::string& routingKey=std::string());
+
+ /** The destination of messages sent to the broker is the exchange
+ * name. The destination of messages received from the broker is
+ * the delivery tag identifyig the local subscription (often this
+ * is the name of the subscribed queue.)
+ */
+ std::string getDestination() const;
+
+ /** Check the redelivered flag. */
+ bool isRedelivered() const;
+ /** Set the redelivered flag. */
+ void setRedelivered(bool redelivered);
+
+ /** Get a modifyable reference to the message headers. */
+ framing::FieldTable& getHeaders();
+
+ /** Get a non-modifyable reference to the message headers. */
+ const framing::FieldTable& getHeaders() const;
+
+ ///@internal
+ const framing::MessageTransferBody& getMethod() const;
+ ///@internal
+ const framing::SequenceNumber& getId() const;
+
+ /**@internal for incoming messages */
+ Message(const framing::FrameSet& frameset);
+
+private:
+ //method and id are only set for received messages:
+ framing::MessageTransferBody method;
+ framing::SequenceNumber id;
+};
+
+}}
+
+#endif /*!_client_Message_h*/
diff --git a/RC9/qpid/cpp/src/qpid/client/MessageListener.cpp b/RC9/qpid/cpp/src/qpid/client/MessageListener.cpp
new file mode 100644
index 0000000000..68ebedeb0d
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/MessageListener.cpp
@@ -0,0 +1,24 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "MessageListener.h"
+
+qpid::client::MessageListener::~MessageListener() {}
diff --git a/RC9/qpid/cpp/src/qpid/client/MessageListener.h b/RC9/qpid/cpp/src/qpid/client/MessageListener.h
new file mode 100644
index 0000000000..75aad6521b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/MessageListener.h
@@ -0,0 +1,100 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <string>
+
+#ifndef _MessageListener_
+#define _MessageListener_
+
+#include "Message.h"
+
+namespace qpid {
+namespace client {
+
+ /**
+ * Implement a subclass of MessageListener and subscribe it using
+ * the SubscriptionManager to receive messages.
+ *
+ * Another way to receive messages is by using a LocalQueue.
+ *
+ * \ingroup clientapi
+ * \details
+ *
+ * <h2>Using a MessageListener</h2>
+ *
+ * <ul>
+ * <li>
+ * <p>The received() function is called when a message arrives:</p>
+ * <pre>virtual void received(Message&amp; message)=0;</pre>
+ * </li>
+ * <li>
+ * <p>Derive your own listener, implement the received() function:</p>
+ * <pre>
+ * class Listener : public MessageListener {
+ * private:
+ * SubscriptionManager&amp; subscriptions;
+ * public:
+ * Listener(SubscriptionManager&amp; subscriptions);
+ * virtual void received(Message&amp; message);
+ * };
+ *
+ * Listener::Listener(SubscriptionManager&amp; subs) : subscriptions(subs)
+ * {}
+ *
+ * void Listener::received(Message&amp; message) {
+ * std::cout &lt;&lt; "Message: " &lt;&lt; message.getData() &lt;&lt; std::endl;
+ * if (message.getData() == "That's all, folks!") {
+ * std::cout &lt;&lt; "Shutting down listener for " &lt;&lt; message.getDestination()
+ * &lt;&lt; std::endl;
+ * subscriptions.cancel(message.getDestination());
+ * }
+ * }
+ *</pre>
+ * <pre>
+ * SubscriptionManager subscriptions(session);
+ *
+ * // Create a listener and subscribe it to the queue named "message_queue"
+ * Listener listener(subscriptions);
+ * subscriptions.subscribe(listener, "message_queue");
+ *
+ * // Receive messages until the subscription is cancelled
+ * // by Listener::received()
+ * subscriptions.run();
+ * </pre>
+ * </li>
+ * </ul>
+ *
+ */
+
+ class MessageListener{
+ public:
+ virtual ~MessageListener();
+
+ /** Called for each message arriving from the broker. Override
+ * in your own subclass to process messages.
+ */
+ virtual void received(Message& msg) = 0;
+ };
+
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/client/MessageReplayTracker.cpp b/RC9/qpid/cpp/src/qpid/client/MessageReplayTracker.cpp
new file mode 100644
index 0000000000..9ffbb76837
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/MessageReplayTracker.cpp
@@ -0,0 +1,80 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "MessageReplayTracker.h"
+#include <boost/bind.hpp>
+
+namespace qpid {
+namespace client {
+
+MessageReplayTracker::MessageReplayTracker(uint f) : flushInterval(f), count(0) {}
+
+void MessageReplayTracker::send(const Message& message, const std::string& destination)
+{
+ buffer.push_back(ReplayRecord(message, destination));
+ buffer.back().send(*this);
+ if (flushInterval && ++count >= flushInterval) {
+ checkCompletion();
+ if (!buffer.empty()) session.flush();
+ }
+}
+void MessageReplayTracker::init(AsyncSession s)
+{
+ session = s;
+}
+
+void MessageReplayTracker::replay(AsyncSession s)
+{
+ session = s;
+ std::list<ReplayRecord> copy;
+ buffer.swap(copy);
+ std::for_each(copy.begin(), copy.end(), boost::bind(&ReplayRecord::send, _1, boost::ref(*this)));
+ session.flush();
+ count = 0;
+}
+
+void MessageReplayTracker::setFlushInterval(uint f)
+{
+ flushInterval = f;
+}
+
+uint MessageReplayTracker::getFlushInterval()
+{
+ return flushInterval;
+}
+
+void MessageReplayTracker::checkCompletion()
+{
+ buffer.remove_if(boost::bind(&ReplayRecord::isComplete, _1));
+}
+
+MessageReplayTracker::ReplayRecord::ReplayRecord(const Message& m, const std::string& d) : message(m), destination(d) {}
+
+void MessageReplayTracker::ReplayRecord::send(MessageReplayTracker& tracker)
+{
+ status = tracker.session.messageTransfer(arg::destination=destination, arg::content=message);
+}
+
+bool MessageReplayTracker::ReplayRecord::isComplete()
+{
+ return status.isComplete();
+}
+
+}} // namespace qpid::client
diff --git a/RC9/qpid/cpp/src/qpid/client/MessageReplayTracker.h b/RC9/qpid/cpp/src/qpid/client/MessageReplayTracker.h
new file mode 100644
index 0000000000..45b16fb704
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/MessageReplayTracker.h
@@ -0,0 +1,73 @@
+#ifndef QPID_CLIENT_MESSAGEREPLAYTRACKER_H
+#define QPID_CLIENT_MESSAGEREPLAYTRACKER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "AsyncSession.h"
+#include "Message.h"
+
+#include <list>
+#include <string>
+
+namespace qpid {
+namespace client {
+
+/**
+ * Utility to track messages sent asynchronously, allowing those that
+ * are indoubt to be replayed over a new session.
+ */
+class MessageReplayTracker
+{
+ public:
+ MessageReplayTracker(uint flushInterval);
+ void send(const Message& message, const std::string& destination = "");
+ void init(AsyncSession session);
+ void replay(AsyncSession session);
+ void setFlushInterval(uint interval);
+ uint getFlushInterval();
+ void checkCompletion();
+
+ template <class F> void foreach(F& f) {
+ for (std::list<ReplayRecord>::const_iterator i = buffer.begin(); i != buffer.end(); i++) {
+ f(i->message);
+ }
+ }
+
+ private:
+ struct ReplayRecord
+ {
+ Completion status;
+ Message message;
+ std::string destination;
+
+ ReplayRecord(const Message& message, const std::string& destination);
+ void send(MessageReplayTracker&);
+ bool isComplete();
+ };
+
+ AsyncSession session;
+ uint flushInterval;
+ uint count;
+ std::list<ReplayRecord> buffer;
+};
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_MESSAGEREPLAYTRACKER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/client/QueueOptions.cpp b/RC9/qpid/cpp/src/qpid/client/QueueOptions.cpp
new file mode 100644
index 0000000000..ac65b0bc22
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/QueueOptions.cpp
@@ -0,0 +1,116 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "QueueOptions.h"
+
+namespace qpid {
+namespace client {
+
+
+QueueOptions::QueueOptions()
+{}
+
+const std::string QueueOptions::strMaxCountKey("qpid.max_count");
+const std::string QueueOptions::strMaxSizeKey("qpid.max_size");
+const std::string QueueOptions::strTypeKey("qpid.policy_type");
+const std::string QueueOptions::strREJECT("reject");
+const std::string QueueOptions::strFLOW_TO_DISK("flow_to_disk");
+const std::string QueueOptions::strRING("ring");
+const std::string QueueOptions::strRING_STRICT("ring_strict");
+const std::string QueueOptions::strLastValueQueue("qpid.last_value_queue");
+const std::string QueueOptions::strPersistLastNode("qpid.persist_last_node");
+const std::string QueueOptions::strLVQMatchProperty("qpid.LVQ_key");
+const std::string QueueOptions::strLastValueQueueNoBrowse("qpid.last_value_queue_no_browse");
+
+
+QueueOptions::~QueueOptions()
+{}
+
+void QueueOptions::setSizePolicy(QueueSizePolicy sp, uint64_t maxSize, uint32_t maxCount)
+{
+ if (maxCount) setInt(strMaxCountKey, maxCount);
+ if (maxSize) setInt(strMaxSizeKey, maxSize);
+ if (maxSize || maxCount){
+ switch (sp)
+ {
+ case REJECT:
+ setString(strTypeKey, strREJECT);
+ break;
+ case FLOW_TO_DISK:
+ setString(strTypeKey, strFLOW_TO_DISK);
+ break;
+ case RING:
+ setString(strTypeKey, strRING);
+ break;
+ case RING_STRICT:
+ setString(strTypeKey, strRING_STRICT);
+ break;
+ case NONE:
+ clearSizePolicy();
+ break;
+ }
+ }
+}
+
+
+void QueueOptions::setPersistLastNode()
+{
+ setInt(strPersistLastNode, 1);
+}
+
+void QueueOptions::setOrdering(QueueOrderingPolicy op)
+{
+ if (op == LVQ){
+ setInt(strLastValueQueue, 1);
+ }else if (op == LVQ_NO_BROWSE){
+ setInt(strLastValueQueueNoBrowse, 1);
+ }else {
+ clearOrdering();
+ }
+}
+
+void QueueOptions::getLVQKey(std::string& key)
+{
+ key.assign(strLVQMatchProperty);
+}
+
+void QueueOptions::clearSizePolicy()
+{
+ erase(strMaxCountKey);
+ erase(strMaxSizeKey);
+ erase(strTypeKey);
+}
+
+void QueueOptions::clearPersistLastNode()
+{
+ erase(strPersistLastNode);
+}
+
+void QueueOptions::clearOrdering()
+{
+ erase(strLastValueQueue);
+}
+
+
+}
+}
+
+
diff --git a/RC9/qpid/cpp/src/qpid/client/QueueOptions.h b/RC9/qpid/cpp/src/qpid/client/QueueOptions.h
new file mode 100644
index 0000000000..114e1e49c2
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/QueueOptions.h
@@ -0,0 +1,104 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/framing/FieldTable.h"
+
+#ifndef _QueueOptions_
+#define _QueueOptions_
+
+namespace qpid {
+namespace client {
+
+enum QueueSizePolicy {NONE, REJECT, FLOW_TO_DISK, RING, RING_STRICT};
+enum QueueOrderingPolicy {FIFO, LVQ, LVQ_NO_BROWSE};
+
+/**
+ * A help class to set options on the Queue. Create a configured args while
+ * still allowing any custom configuration via the FieldTable base class
+ */
+class QueueOptions: public framing::FieldTable
+{
+ public:
+ QueueOptions();
+ virtual ~QueueOptions();
+
+ /**
+ * Sets the queue sizing plocy
+ *
+ * @param sp SizePolicy
+ * REJECT - reject if queue greater than size/count
+ * FLOW_TO_DISK - page messages to disk from this point is greater than size/count
+ * RING - limit the queue to size/count and over-write old messages round a ring
+ * RING_STRICT - limit the queue to size/count and reject is head == tail
+ * NONE - Use default broker sizing policy
+ * @param maxSize Set the max number of bytes for the sizing policies
+ * @param setMaxCount Set the max number of messages for the sizing policies
+ */
+ void setSizePolicy(QueueSizePolicy sp, uint64_t maxSize, uint32_t maxCount );
+
+ /**
+ * Enables the persisting of a queue to the store module when a cluster fails down to it's last
+ * node. Does so optimistically. Will start persisting when cluster count >1 again.
+ */
+ void setPersistLastNode();
+
+ /**
+ * Sets the odering policy on the Queue, default ordering is FIFO.
+ */
+ void setOrdering(QueueOrderingPolicy op);
+
+ /**
+ * Use broker defualt sizing ploicy
+ */
+ void clearSizePolicy();
+
+ /**
+ * Clear Persist Last Node Policy
+ */
+ void clearPersistLastNode();
+
+ /**
+ * get the key used match LVQ in args for message transfer
+ */
+ void getLVQKey(std::string& key);
+
+ /**
+ * Use default odering policy
+ */
+ void clearOrdering();
+
+ static const std::string strMaxCountKey;
+ static const std::string strMaxSizeKey;
+ static const std::string strTypeKey;
+ static const std::string strREJECT;
+ static const std::string strFLOW_TO_DISK;
+ static const std::string strRING;
+ static const std::string strRING_STRICT;
+ static const std::string strLastValueQueue;
+ static const std::string strPersistLastNode;
+ static const std::string strLVQMatchProperty;
+ static const std::string strLastValueQueueNoBrowse;
+};
+
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/client/RdmaConnector.cpp b/RC9/qpid/cpp/src/qpid/client/RdmaConnector.cpp
new file mode 100644
index 0000000000..98fe762f31
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/RdmaConnector.cpp
@@ -0,0 +1,428 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "Connector.h"
+
+#include "Bounds.h"
+#include "ConnectionImpl.h"
+#include "ConnectionSettings.h"
+#include "qpid/log/Statement.h"
+#include "qpid/sys/Time.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/sys/rdma/RdmaIO.h"
+#include "qpid/sys/Dispatcher.h"
+#include "qpid/sys/Poller.h"
+#include "qpid/Msg.h"
+
+#include <iostream>
+#include <boost/bind.hpp>
+#include <boost/format.hpp>
+#include <boost/lexical_cast.hpp>
+
+// This stuff needs to abstracted out of here to a platform specific file
+#include <netdb.h>
+
+namespace qpid {
+namespace client {
+
+using namespace qpid::sys;
+using namespace qpid::framing;
+using boost::format;
+using boost::str;
+
+class RdmaConnector : public Connector, private sys::Runnable
+{
+ struct Buff;
+
+ /** Batch up frames for writing to aio. */
+ class Writer : public framing::FrameHandler {
+ typedef Rdma::Buffer BufferBase;
+ typedef std::deque<framing::AMQFrame> Frames;
+
+ const uint16_t maxFrameSize;
+ sys::Mutex lock;
+ Rdma::AsynchIO* aio;
+ BufferBase* buffer;
+ Frames frames;
+ size_t lastEof; // Position after last EOF in frames
+ framing::Buffer encode;
+ size_t framesEncoded;
+ std::string identifier;
+ Bounds* bounds;
+
+ void writeOne();
+ void newBuffer();
+
+ public:
+
+ Writer(uint16_t maxFrameSize, Bounds*);
+ ~Writer();
+ void init(std::string id, Rdma::AsynchIO*);
+ void handle(framing::AMQFrame&);
+ void write(Rdma::AsynchIO&);
+ };
+
+ const uint16_t maxFrameSize;
+ framing::ProtocolVersion version;
+ bool initiated;
+
+ sys::Mutex pollingLock;
+ bool polling;
+ bool joined;
+
+ sys::ShutdownHandler* shutdownHandler;
+ framing::InputHandler* input;
+ framing::InitiationHandler* initialiser;
+ framing::OutputHandler* output;
+
+ Writer writer;
+
+ sys::Thread receiver;
+
+ Rdma::AsynchIO* aio;
+ sys::Poller::shared_ptr poller;
+
+ ~RdmaConnector();
+
+ void run();
+ void handleClosed();
+ bool closeInternal();
+
+ // Callbacks
+ void connected(sys::Poller::shared_ptr, Rdma::Connection::intrusive_ptr&, const Rdma::ConnectionParams&);
+ void connectionError(sys::Poller::shared_ptr, Rdma::Connection::intrusive_ptr&, Rdma::ErrorType);
+ void disconnected(sys::Poller::shared_ptr, Rdma::Connection::intrusive_ptr&);
+ void rejected(sys::Poller::shared_ptr, Rdma::Connection::intrusive_ptr&, const Rdma::ConnectionParams&);
+
+ void readbuff(Rdma::AsynchIO&, Rdma::Buffer*);
+ void writebuff(Rdma::AsynchIO&);
+ void writeDataBlock(const framing::AMQDataBlock& data);
+ void eof(Rdma::AsynchIO&);
+
+ std::string identifier;
+
+ ConnectionImpl* impl;
+
+ void connect(const std::string& host, int port);
+ void close();
+ void send(framing::AMQFrame& frame);
+
+ void setInputHandler(framing::InputHandler* handler);
+ void setShutdownHandler(sys::ShutdownHandler* handler);
+ sys::ShutdownHandler* getShutdownHandler() const;
+ framing::OutputHandler* getOutputHandler();
+ const std::string& getIdentifier() const;
+
+public:
+ RdmaConnector(framing::ProtocolVersion pVersion,
+ const ConnectionSettings&,
+ ConnectionImpl*);
+};
+
+// Static constructor which registers connector here
+namespace {
+ Connector* create(framing::ProtocolVersion v, const ConnectionSettings& s, ConnectionImpl* c) {
+ return new RdmaConnector(v, s, c);
+ }
+
+ struct StaticInit {
+ StaticInit() {
+ Connector::registerFactory("rdma", &create);
+ Connector::registerFactory("ib", &create);
+ };
+ } init;
+}
+
+
+RdmaConnector::RdmaConnector(ProtocolVersion ver,
+ const ConnectionSettings& settings,
+ ConnectionImpl* cimpl)
+ : maxFrameSize(settings.maxFrameSize),
+ version(ver),
+ initiated(false),
+ polling(false),
+ joined(true),
+ shutdownHandler(0),
+ writer(maxFrameSize, cimpl),
+ aio(0),
+ impl(cimpl)
+{
+ QPID_LOG(debug, "RdmaConnector created for " << version);
+}
+
+RdmaConnector::~RdmaConnector() {
+ close();
+}
+
+void RdmaConnector::connect(const std::string& host, int port){
+ Mutex::ScopedLock l(pollingLock);
+ assert(!polling);
+ assert(joined);
+ poller = Poller::shared_ptr(new Poller);
+
+ // This stuff needs to abstracted out of here to a platform specific file
+ ::addrinfo *res;
+ ::addrinfo hints;
+ hints.ai_flags = 0;
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = 0;
+ int n = ::getaddrinfo(host.c_str(), boost::lexical_cast<std::string>(port).c_str(), &hints, &res);
+ if (n<0) {
+ throw Exception(QPID_MSG("Cannot resolve " << host << ": " << ::gai_strerror(n)));
+ }
+
+ Rdma::Connector* c = new Rdma::Connector(
+ *res->ai_addr,
+ Rdma::ConnectionParams(maxFrameSize, Rdma::DEFAULT_WR_ENTRIES),
+ boost::bind(&RdmaConnector::connected, this, poller, _1, _2),
+ boost::bind(&RdmaConnector::connectionError, this, poller, _1, _2),
+ boost::bind(&RdmaConnector::disconnected, this, poller, _1),
+ boost::bind(&RdmaConnector::rejected, this, poller, _1, _2));
+ c->start(poller);
+
+ polling = true;
+ joined = false;
+ receiver = Thread(this);
+}
+
+// The following only gets run when connected
+void RdmaConnector::connected(Poller::shared_ptr poller, Rdma::Connection::intrusive_ptr& ci, const Rdma::ConnectionParams& cp) {
+ Rdma::QueuePair::intrusive_ptr q = ci->getQueuePair();
+
+ aio = new Rdma::AsynchIO(ci->getQueuePair(),
+ cp.maxRecvBufferSize, cp.initialXmitCredit , Rdma::DEFAULT_WR_ENTRIES,
+ boost::bind(&RdmaConnector::readbuff, this, _1, _2),
+ boost::bind(&RdmaConnector::writebuff, this, _1),
+ 0, // write buffers full
+ boost::bind(&RdmaConnector::eof, this, _1)); // data error - just close connection
+ aio->start(poller);
+
+ identifier = str(format("[%1% %2%]") % ci->getLocalName() % ci->getPeerName());
+ writer.init(identifier, aio);
+ ProtocolInitiation init(version);
+ writeDataBlock(init);
+}
+
+void RdmaConnector::connectionError(sys::Poller::shared_ptr, Rdma::Connection::intrusive_ptr&, Rdma::ErrorType) {
+ QPID_LOG(trace, "Connection Error " << identifier);
+ eof(*aio);
+}
+
+void RdmaConnector::disconnected(sys::Poller::shared_ptr, Rdma::Connection::intrusive_ptr&) {
+ eof(*aio);
+}
+
+void RdmaConnector::rejected(sys::Poller::shared_ptr, Rdma::Connection::intrusive_ptr&, const Rdma::ConnectionParams& cp) {
+ QPID_LOG(trace, "Connection Rejected " << identifier << ": " << cp.maxRecvBufferSize);
+ eof(*aio);
+}
+
+bool RdmaConnector::closeInternal() {
+ bool ret;
+ {
+ Mutex::ScopedLock l(pollingLock);
+ ret = polling;
+ if (polling) {
+ polling = false;
+ poller->shutdown();
+ }
+ if (joined || receiver.id() == Thread::current().id()) {
+ return ret;
+ }
+ joined = true;
+ }
+
+ receiver.join();
+ return ret;
+}
+
+void RdmaConnector::close() {
+ closeInternal();
+}
+
+void RdmaConnector::setInputHandler(InputHandler* handler){
+ input = handler;
+}
+
+void RdmaConnector::setShutdownHandler(ShutdownHandler* handler){
+ shutdownHandler = handler;
+}
+
+OutputHandler* RdmaConnector::getOutputHandler(){
+ return this;
+}
+
+sys::ShutdownHandler* RdmaConnector::getShutdownHandler() const {
+ return shutdownHandler;
+}
+
+const std::string& RdmaConnector::getIdentifier() const {
+ return identifier;
+}
+
+void RdmaConnector::send(AMQFrame& frame) {
+ writer.handle(frame);
+}
+
+void RdmaConnector::handleClosed() {
+ if (closeInternal() && shutdownHandler)
+ shutdownHandler->shutdown();
+}
+
+RdmaConnector::Writer::Writer(uint16_t s, Bounds* b) :
+ maxFrameSize(s),
+ aio(0),
+ buffer(0),
+ lastEof(0),
+ bounds(b)
+{
+}
+
+RdmaConnector::Writer::~Writer() {
+ if (aio)
+ aio->returnBuffer(buffer);
+}
+
+void RdmaConnector::Writer::init(std::string id, Rdma::AsynchIO* a) {
+ Mutex::ScopedLock l(lock);
+ identifier = id;
+ aio = a;
+ assert(aio->bufferAvailable());
+ newBuffer();
+}
+void RdmaConnector::Writer::handle(framing::AMQFrame& frame) {
+ Mutex::ScopedLock l(lock);
+ frames.push_back(frame);
+ // Don't bother to send anything unless we're at the end of a frameset (assembly in 0-10 terminology)
+ if (frame.getEof()) {
+ lastEof = frames.size();
+ QPID_LOG(debug, "Requesting write: lastEof=" << lastEof);
+ aio->notifyPendingWrite();
+ }
+ QPID_LOG(trace, "SENT " << identifier << ": " << frame);
+}
+
+void RdmaConnector::Writer::writeOne() {
+ assert(buffer);
+ QPID_LOG(trace, "Write buffer " << encode.getPosition()
+ << " bytes " << framesEncoded << " frames ");
+ framesEncoded = 0;
+
+ buffer->dataStart = 0;
+ buffer->dataCount = encode.getPosition();
+ aio->queueWrite(buffer);
+ newBuffer();
+}
+
+void RdmaConnector::Writer::newBuffer() {
+ buffer = aio->getBuffer();
+ encode = framing::Buffer(buffer->bytes, buffer->byteCount);
+ framesEncoded = 0;
+}
+
+// Called in IO thread. (write idle routine)
+// This is NOT only called in response to previously calling notifyPendingWrite
+void RdmaConnector::Writer::write(Rdma::AsynchIO&) {
+ Mutex::ScopedLock l(lock);
+ assert(buffer);
+ // If nothing to do return immediately
+ if (lastEof==0)
+ return;
+ size_t bytesWritten = 0;
+ while (aio->writable() && aio->bufferAvailable() && !frames.empty()) {
+ const AMQFrame* frame = &frames.front();
+ uint32_t size = frame->encodedSize();
+ while (size <= encode.available()) {
+ frame->encode(encode);
+ frames.pop_front();
+ ++framesEncoded;
+ bytesWritten += size;
+ if (frames.empty())
+ break;
+ frame = &frames.front();
+ size = frame->encodedSize();
+ }
+ lastEof -= framesEncoded;
+ writeOne();
+ }
+ if (bounds) bounds->reduce(bytesWritten);
+}
+
+void RdmaConnector::readbuff(Rdma::AsynchIO&, Rdma::Buffer* buff) {
+ framing::Buffer in(buff->bytes+buff->dataStart, buff->dataCount);
+
+ if (!initiated) {
+ framing::ProtocolInitiation protocolInit;
+ if (protocolInit.decode(in)) {
+ //TODO: check the version is correct
+ QPID_LOG(debug, "RECV " << identifier << " INIT(" << protocolInit << ")");
+ }
+ initiated = true;
+ }
+ AMQFrame frame;
+ while(frame.decode(in)){
+ QPID_LOG(trace, "RECV " << identifier << ": " << frame);
+ input->received(frame);
+ }
+}
+
+void RdmaConnector::writebuff(Rdma::AsynchIO& aio_) {
+ writer.write(aio_);
+}
+
+void RdmaConnector::writeDataBlock(const AMQDataBlock& data) {
+ Rdma::Buffer* buff = aio->getBuffer();
+ framing::Buffer out(buff->bytes, buff->byteCount);
+ data.encode(out);
+ buff->dataCount = data.encodedSize();
+ aio->queueWrite(buff);
+}
+
+void RdmaConnector::eof(Rdma::AsynchIO&) {
+ handleClosed();
+}
+
+// TODO: astitcher 20070908 This version of the code can never time out, so the idle processing
+// will never be called
+void RdmaConnector::run(){
+ // Keep the connection impl in memory until run() completes.
+ //GRS: currently the ConnectionImpls destructor is where the Io thread is joined
+ //boost::shared_ptr<ConnectionImpl> protect = impl->shared_from_this();
+ //assert(protect);
+ try {
+ Dispatcher d(poller);
+
+ //aio->start(poller);
+ d.run();
+ //aio->queueForDeletion();
+ } catch (const std::exception& e) {
+ {
+ // We're no longer polling
+ Mutex::ScopedLock l(pollingLock);
+ polling = false;
+ }
+ QPID_LOG(error, e.what());
+ handleClosed();
+ }
+}
+
+
+}} // namespace qpid::client
diff --git a/RC9/qpid/cpp/src/qpid/client/Results.cpp b/RC9/qpid/cpp/src/qpid/client/Results.cpp
new file mode 100644
index 0000000000..1b98d6c98a
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/Results.cpp
@@ -0,0 +1,76 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Results.h"
+#include "FutureResult.h"
+#include "qpid/framing/SequenceSet.h"
+
+using namespace qpid::framing;
+using namespace boost;
+
+namespace qpid {
+namespace client {
+
+Results::Results() {}
+
+Results::~Results() {
+ try { close(); } catch (const std::exception& /*e*/) { assert(0); }
+}
+
+void Results::close()
+{
+ for (Listeners::iterator i = listeners.begin(); i != listeners.end(); i++) {
+ i->second->completed();
+ }
+ listeners.clear();
+}
+
+void Results::completed(const SequenceSet& set)
+{
+ //call complete on those listeners whose ids fall within the set
+ Listeners::iterator i = listeners.begin();
+ while (i != listeners.end()) {
+ if (set.contains(i->first)) {
+ i->second->completed();
+ listeners.erase(i++);
+ } else {
+ i++;
+ }
+ }
+}
+
+void Results::received(const SequenceNumber& id, const std::string& result)
+{
+ Listeners::iterator i = listeners.find(id);
+ if (i != listeners.end()) {
+ i->second->received(result);
+ listeners.erase(i);
+ }
+}
+
+Results::FutureResultPtr Results::listenForResult(const SequenceNumber& id)
+{
+ FutureResultPtr l(new FutureResult());
+ listeners[id] = l;
+ return l;
+}
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/client/Results.h b/RC9/qpid/cpp/src/qpid/client/Results.h
new file mode 100644
index 0000000000..4c49f6b05b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/Results.h
@@ -0,0 +1,56 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/framing/SequenceNumber.h"
+#include <map>
+#include <boost/shared_ptr.hpp>
+
+#ifndef _Results_
+#define _Results_
+
+namespace qpid {
+namespace client {
+
+class FutureResult;
+
+///@internal
+class Results
+{
+public:
+ typedef boost::shared_ptr<FutureResult> FutureResultPtr;
+
+ Results();
+ ~Results();
+ void completed(const framing::SequenceSet& set);
+ void received(const framing::SequenceNumber& id, const std::string& result);
+ FutureResultPtr listenForResult(const framing::SequenceNumber& point);
+ void close();
+
+private:
+ typedef std::map<framing::SequenceNumber, FutureResultPtr> Listeners;
+ Listeners listeners;
+};
+
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/client/Session.h b/RC9/qpid/cpp/src/qpid/client/Session.h
new file mode 100644
index 0000000000..bdabd26c82
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/Session.h
@@ -0,0 +1,39 @@
+#ifndef QPID_CLIENT_SESSION_H
+#define QPID_CLIENT_SESSION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/client/Session_0_10.h"
+
+namespace qpid {
+namespace client {
+
+/**
+ * Session is an alias for Session_0_10
+ *
+ * \ingroup clientapi
+ */
+typedef Session_0_10 Session;
+
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_SESSION_H*/
diff --git a/RC9/qpid/cpp/src/qpid/client/SessionBase_0_10.cpp b/RC9/qpid/cpp/src/qpid/client/SessionBase_0_10.cpp
new file mode 100644
index 0000000000..c933a64f07
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/SessionBase_0_10.cpp
@@ -0,0 +1,77 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "SessionBase_0_10.h"
+#include "Connection.h"
+#include "qpid/framing/all_method_bodies.h"
+
+namespace qpid {
+namespace client {
+
+using namespace framing;
+
+SessionBase_0_10::SessionBase_0_10() {}
+SessionBase_0_10::~SessionBase_0_10() {}
+
+void SessionBase_0_10::close() { impl->close(); }
+
+Execution& SessionBase_0_10::getExecution()
+{
+ return *impl;
+}
+
+void SessionBase_0_10::flush()
+{
+ impl->sendFlush();
+}
+
+void SessionBase_0_10::sync()
+{
+ ExecutionSyncBody b;
+ b.setSync(true);
+ impl->send(b).wait(*impl);
+}
+
+void SessionBase_0_10::markCompleted(const framing::SequenceSet& ids, bool notifyPeer)
+{
+ impl->markCompleted(ids, notifyPeer);
+}
+
+void SessionBase_0_10::markCompleted(const framing::SequenceNumber& id, bool cumulative, bool notifyPeer)
+{
+ impl->markCompleted(id, cumulative, notifyPeer);
+}
+
+void SessionBase_0_10::sendCompletion()
+{
+ impl->sendCompletion();
+}
+
+uint16_t SessionBase_0_10::getChannel() const { return impl->getChannel(); }
+
+void SessionBase_0_10::suspend() { impl->suspend(); }
+void SessionBase_0_10::resume(Connection c) { impl->resume(c.impl); }
+uint32_t SessionBase_0_10::timeout(uint32_t seconds) { return impl->setTimeout(seconds); }
+
+SessionId SessionBase_0_10::getId() const { return impl->getId(); }
+framing::FrameSet::shared_ptr SessionBase_0_10::get() { return impl->get(); }
+
+
+}} // namespace qpid::client
diff --git a/RC9/qpid/cpp/src/qpid/client/SessionBase_0_10.h b/RC9/qpid/cpp/src/qpid/client/SessionBase_0_10.h
new file mode 100644
index 0000000000..091c977053
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/SessionBase_0_10.h
@@ -0,0 +1,118 @@
+#ifndef QPID_CLIENT_SESSIONBASE_H
+#define QPID_CLIENT_SESSIONBASE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/SessionId.h"
+#include "qpid/framing/amqp_structs.h"
+#include "qpid/framing/ProtocolVersion.h"
+#include "qpid/framing/MethodContent.h"
+#include "qpid/framing/TransferContent.h"
+#include "qpid/client/Completion.h"
+#include "qpid/client/ConnectionImpl.h"
+#include "qpid/client/Execution.h"
+#include "qpid/client/SessionImpl.h"
+#include "qpid/client/TypedResult.h"
+#include "qpid/shared_ptr.h"
+#include <string>
+
+namespace qpid {
+namespace client {
+
+class Connection;
+
+using std::string;
+using framing::Content;
+using framing::FieldTable;
+using framing::MethodContent;
+using framing::SequenceNumber;
+using framing::SequenceSet;
+using framing::SequenceNumberSet;
+using qpid::SessionId;
+using framing::Xid;
+
+/** Unit of message credit: messages or bytes */
+enum CreditUnit { MESSAGE_CREDIT=0, BYTE_CREDIT=1, UNLIMITED_CREDIT=0xFFFFFFFF };
+
+/**
+ * Base class for handles to an AMQP session.
+ *
+ * Subclasses provide the AMQP commands for a given
+ * version of the protocol.
+ */
+class SessionBase_0_10 {
+ public:
+
+ typedef framing::TransferContent DefaultContent;
+
+ ///@internal
+ SessionBase_0_10();
+ ~SessionBase_0_10();
+
+ /** Get the next message frame-set from the session. */
+ framing::FrameSet::shared_ptr get();
+
+ /** Get the session ID */
+ SessionId getId() const;
+
+ /** Close the session.
+ * A session is automatically closed when all handles to it are destroyed.
+ */
+ void close();
+
+ /**
+ * Synchronize the session: sync() waits until all commands issued
+ * on this session so far have been completed by the broker.
+ *
+ * Note sync() is always synchronous, even on an AsyncSession object
+ * because that's almost always what you want. You can call
+ * AsyncSession::executionSync() directly in the unusual event
+ * that you want to do an asynchronous sync.
+ */
+ void sync();
+
+ /** Set the timeout for this session. */
+ uint32_t timeout(uint32_t seconds);
+
+ /** Suspend the session - detach it from its connection */
+ void suspend();
+
+ /** Resume a suspended session with a new connection */
+ void resume(Connection);
+
+ /** Get the channel associated with this session */
+ uint16_t getChannel() const;
+
+ Execution& getExecution();
+ void flush();
+ void markCompleted(const framing::SequenceSet& ids, bool notifyPeer);
+ void markCompleted(const framing::SequenceNumber& id, bool cumulative, bool notifyPeer);
+ void sendCompletion();
+
+ protected:
+ boost::shared_ptr<SessionImpl> impl;
+ friend class SessionBase_0_10Access;
+};
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_SESSIONBASE_H*/
diff --git a/RC9/qpid/cpp/src/qpid/client/SessionBase_0_10Access.h b/RC9/qpid/cpp/src/qpid/client/SessionBase_0_10Access.h
new file mode 100644
index 0000000000..e2189a53dd
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/SessionBase_0_10Access.h
@@ -0,0 +1,42 @@
+#ifndef QPID_CLIENT_SESSIONBASEACCESS_H
+#define QPID_CLIENT_SESSIONBASEACCESS_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/client/SessionBase_0_10.h"
+
+/**@file @internal Internal use only */
+
+namespace qpid {
+namespace client {
+
+class SessionBase_0_10Access {
+ public:
+ SessionBase_0_10Access(SessionBase_0_10& sb_) : sb(sb_) {}
+ void set(const boost::shared_ptr<SessionImpl>& si) { sb.impl = si; }
+ boost::shared_ptr<SessionImpl> get() { return sb.impl; }
+ private:
+ SessionBase_0_10& sb;
+};
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_SESSIONBASEACCESS_H*/
diff --git a/RC9/qpid/cpp/src/qpid/client/SessionImpl.cpp b/RC9/qpid/cpp/src/qpid/client/SessionImpl.cpp
new file mode 100644
index 0000000000..ab8c1bddb8
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/SessionImpl.cpp
@@ -0,0 +1,695 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "SessionImpl.h"
+
+#include "ConnectionImpl.h"
+#include "Future.h"
+
+#include "qpid/framing/all_method_bodies.h"
+#include "qpid/framing/ClientInvoker.h"
+#include "qpid/framing/enum.h"
+#include "qpid/framing/FrameSet.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/MethodContent.h"
+#include "qpid/framing/SequenceSet.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/framing/DeliveryProperties.h"
+#include "qpid/log/Statement.h"
+#include "qpid/sys/IntegerTypes.h"
+
+#include <boost/bind.hpp>
+
+namespace { const std::string EMPTY; }
+
+namespace qpid {
+namespace client {
+
+using namespace qpid::framing;
+using namespace qpid::framing::session; //for detach codes
+
+typedef sys::Monitor::ScopedLock Lock;
+typedef sys::Monitor::ScopedUnlock UnLock;
+typedef sys::ScopedLock<sys::Semaphore> Acquire;
+
+
+SessionImpl::SessionImpl(const std::string& name, shared_ptr<ConnectionImpl> conn)
+ : state(INACTIVE),
+ detachedLifetime(0),
+ maxFrameSize(conn->getNegotiatedSettings().maxFrameSize),
+ id(conn->getNegotiatedSettings().username, name.empty() ? Uuid(true).str() : name),
+ connectionShared(conn),
+ connectionWeak(conn),
+ weakPtr(false),
+ ioHandler(*this),
+ proxy(ioHandler),
+ nextIn(0),
+ nextOut(0)
+{
+ channel.next = connectionShared.get();
+}
+
+SessionImpl::~SessionImpl() {
+ {
+ Lock l(state);
+ if (state != DETACHED) {
+ QPID_LOG(warning, "Session was not closed cleanly");
+ setState(DETACHED);
+ handleClosed();
+ state.waitWaiters();
+ }
+ }
+ boost::shared_ptr<ConnectionImpl> c = connectionWeak.lock();
+ if (c) c->erase(channel);
+}
+
+
+FrameSet::shared_ptr SessionImpl::get() // user thread
+{
+ // No lock here: pop does a blocking wait.
+ return demux.getDefault()->pop();
+}
+
+const SessionId SessionImpl::getId() const //user thread
+{
+ return id; //id is immutable
+}
+
+void SessionImpl::open(uint32_t timeout) // user thread
+{
+ Lock l(state);
+ if (state == INACTIVE) {
+ setState(ATTACHING);
+ proxy.attach(id.getName(), false);
+ waitFor(ATTACHED);
+ //TODO: timeout will not be set locally until get response to
+ //confirm, should we wait for that?
+ setTimeout(timeout);
+ proxy.commandPoint(nextOut, 0);
+ } else {
+ throw Exception("Open already called for this session");
+ }
+}
+
+void SessionImpl::close() //user thread
+{
+ Lock l(state);
+ if (detachedLifetime) setTimeout(0);
+ detach();
+ waitFor(DETACHED);
+}
+
+void SessionImpl::resume(shared_ptr<ConnectionImpl>) // user thread
+{
+ // weakPtr sessions should not be resumed.
+ if (weakPtr) return;
+ throw NotImplementedException("Resume not yet implemented by client!");
+}
+
+void SessionImpl::suspend() //user thread
+{
+ Lock l(state);
+ detach();
+}
+
+void SessionImpl::detach() //call with lock held
+{
+ if (state == ATTACHED) {
+ setState(DETACHING);
+ proxy.detach(id.getName());
+ }
+}
+
+
+uint16_t SessionImpl::getChannel() const // user thread
+{
+ return channel;
+}
+
+void SessionImpl::setChannel(uint16_t c) // user thread
+{
+ //channel will only ever be set when session is detached (and
+ //about to be resumed)
+ channel = c;
+}
+
+Demux& SessionImpl::getDemux()
+{
+ return demux;
+}
+
+void SessionImpl::waitForCompletion(const SequenceNumber& id)
+{
+ Lock l(state);
+ waitForCompletionImpl(id);
+}
+
+void SessionImpl::waitForCompletionImpl(const SequenceNumber& id) //call with lock held
+{
+ while (incompleteOut.contains(id)) {
+ checkOpen();
+ state.wait();
+ }
+}
+
+bool SessionImpl::isComplete(const SequenceNumber& id)
+{
+ Lock l(state);
+ return !incompleteOut.contains(id);
+}
+
+struct IsCompleteUpTo
+{
+ const SequenceNumber& id;
+ bool result;
+
+ IsCompleteUpTo(const SequenceNumber& _id) : id(_id), result(true) {}
+ void operator()(const SequenceNumber& start, const SequenceNumber&)
+ {
+ if (start <= id) result = false;
+ }
+
+};
+
+bool SessionImpl::isCompleteUpTo(const SequenceNumber& id)
+{
+ Lock l(state);
+ //return false if incompleteOut contains anything less than id,
+ //true otherwise
+ IsCompleteUpTo f(id);
+ incompleteIn.for_each(f);
+ return f.result;
+}
+
+struct MarkCompleted
+{
+ const SequenceNumber& id;
+ SequenceSet& completedIn;
+
+ MarkCompleted(const SequenceNumber& _id, SequenceSet& set) : id(_id), completedIn(set) {}
+
+ void operator()(const SequenceNumber& start, const SequenceNumber& end)
+ {
+ if (id >= end) {
+ completedIn.add(start, end);
+ } else if (id >= start) {
+ completedIn.add(start, id);
+ }
+ }
+
+};
+
+void SessionImpl::markCompleted(const SequenceSet& ids, bool notifyPeer)
+{
+ Lock l(state);
+ incompleteIn.remove(ids);
+ completedIn.add(ids);
+ if (notifyPeer) {
+ sendCompletion();
+ }
+}
+
+void SessionImpl::markCompleted(const SequenceNumber& id, bool cumulative, bool notifyPeer)
+{
+ Lock l(state);
+ if (cumulative) {
+ //everything in incompleteIn less than or equal to id is now complete
+ MarkCompleted f(id, completedIn);
+ incompleteIn.for_each(f);
+ //make sure id itself is in
+ completedIn.add(id);
+ //then remove anything thats completed from the incomplete set
+ incompleteIn.remove(completedIn);
+ } else if (incompleteIn.contains(id)) {
+ incompleteIn.remove(id);
+ completedIn.add(id);
+ }
+ if (notifyPeer) {
+ sendCompletion();
+ }
+}
+
+void SessionImpl::setException(const sys::ExceptionHolder& ex) {
+ Lock l(state);
+ setExceptionLH(ex);
+}
+
+void SessionImpl::setExceptionLH(const sys::ExceptionHolder& ex) { // Call with lock held.
+ exceptionHolder = ex;
+ setState(DETACHED);
+}
+
+/**
+ * Called by ConnectionImpl to notify active sessions when connection
+ * is explictly closed
+ */
+void SessionImpl::connectionClosed(uint16_t code, const std::string& text) {
+ setException(createConnectionException(code, text));
+ handleClosed();
+}
+
+/**
+ * Called by ConnectionImpl to notify active sessions when connection
+ * is disconnected
+ */
+void SessionImpl::connectionBroke(const std::string& _text) {
+ setException(sys::ExceptionHolder(new TransportFailure(_text)));
+ handleClosed();
+}
+
+Future SessionImpl::send(const AMQBody& command)
+{
+ return sendCommand(command);
+}
+
+Future SessionImpl::send(const AMQBody& command, const MethodContent& content)
+{
+ return sendCommand(command, &content);
+}
+
+namespace {
+// Functor for FrameSet::map to send header + content frames but, not method frames.
+struct SendContentFn {
+ FrameHandler& handler;
+ void operator()(const AMQFrame& f) {
+ if (!f.getMethod())
+ handler(const_cast<AMQFrame&>(f));
+ }
+ SendContentFn(FrameHandler& h) : handler(h) {}
+};
+}
+
+Future SessionImpl::send(const AMQBody& command, const FrameSet& content) {
+ Acquire a(sendLock);
+ SequenceNumber id = nextOut++;
+ {
+ Lock l(state);
+ checkOpen();
+ incompleteOut.add(id);
+ }
+ Future f(id);
+ if (command.getMethod()->resultExpected()) {
+ Lock l(state);
+ //result listener must be set before the command is sent
+ f.setFutureResult(results.listenForResult(id));
+ }
+ AMQFrame frame(command);
+ frame.setEof(false);
+ handleOut(frame);
+
+ SendContentFn send(out);
+ content.map(send);
+ return f;
+}
+
+Future SessionImpl::sendCommand(const AMQBody& command, const MethodContent* content)
+{
+ Acquire a(sendLock);
+ SequenceNumber id = nextOut++;
+ {
+ Lock l(state);
+ checkOpen();
+ incompleteOut.add(id);
+ }
+ Future f(id);
+ if (command.getMethod()->resultExpected()) {
+ Lock l(state);
+ //result listener must be set before the command is sent
+ f.setFutureResult(results.listenForResult(id));
+ }
+ AMQFrame frame(command);
+ if (content) {
+ frame.setEof(false);
+ }
+ handleOut(frame);
+ if (content) {
+ sendContent(*content);
+ }
+ return f;
+}
+
+void SessionImpl::sendContent(const MethodContent& content)
+{
+ AMQFrame header(content.getHeader());
+
+ // Client is not allowed to set the delivery-properties.exchange.
+ AMQHeaderBody* headerp = static_cast<AMQHeaderBody*>(header.getBody());
+ if (headerp && headerp->get<DeliveryProperties>())
+ headerp->get<DeliveryProperties>(true)->clearExchangeFlag();
+
+ header.setFirstSegment(false);
+ uint64_t data_length = content.getData().length();
+ if(data_length > 0){
+ header.setLastSegment(false);
+ handleOut(header);
+ /*Note: end of frame marker included in overhead but not in size*/
+ const uint32_t frag_size = maxFrameSize - AMQFrame::frameOverhead();
+
+ if(data_length < frag_size){
+ AMQFrame frame(in_place<AMQContentBody>(content.getData()));
+ frame.setFirstSegment(false);
+ handleOut(frame);
+ }else{
+ uint32_t offset = 0;
+ uint32_t remaining = data_length - offset;
+ while (remaining > 0) {
+ uint32_t length = remaining > frag_size ? frag_size : remaining;
+ string frag(content.getData().substr(offset, length));
+ AMQFrame frame(in_place<AMQContentBody>(frag));
+ frame.setFirstSegment(false);
+ frame.setLastSegment(true);
+ if (offset > 0) {
+ frame.setFirstFrame(false);
+ }
+ offset += length;
+ remaining = data_length - offset;
+ if (remaining) {
+ frame.setLastFrame(false);
+ }
+ handleOut(frame);
+ }
+ }
+ } else {
+ handleOut(header);
+ }
+}
+
+
+bool isMessageMethod(AMQMethodBody* method)
+{
+ return method->isA<MessageTransferBody>();
+}
+
+bool isMessageMethod(AMQBody* body)
+{
+ AMQMethodBody* method=body->getMethod();
+ return method && isMessageMethod(method);
+}
+
+bool isContentFrame(AMQFrame& frame)
+{
+ AMQBody* body = frame.getBody();
+ uint8_t type = body->type();
+ return type == HEADER_BODY || type == CONTENT_BODY || isMessageMethod(body);
+}
+
+void SessionImpl::handleIn(AMQFrame& frame) // network thread
+{
+ try {
+ if (!invoke(static_cast<SessionHandler&>(*this), *frame.getBody())) {
+ if (invoke(static_cast<ExecutionHandler&>(*this), *frame.getBody())) {
+ //make sure the command id sequence and completion
+ //tracking takes account of execution commands
+ Lock l(state);
+ completedIn.add(nextIn++);
+ } else {
+ //if not handled by this class, its for the application:
+ deliver(frame);
+ }
+ }
+ }
+ catch (const SessionException& e) {
+ setException(createSessionException(e.code, e.getMessage()));
+ }
+ catch (const ChannelException& e) {
+ setException(createChannelException(e.code, e.getMessage()));
+ }
+}
+
+void SessionImpl::handleOut(AMQFrame& frame) // user thread
+{
+ sendFrame(frame, true);
+}
+
+void SessionImpl::proxyOut(AMQFrame& frame) // network thread
+{
+ //Note: this case is treated slightly differently that command
+ //frames sent by application; session controls should not be
+ //blocked by bounds checking on the outgoing frame queue.
+ sendFrame(frame, false);
+}
+
+void SessionImpl::sendFrame(AMQFrame& frame, bool canBlock)
+{
+ boost::shared_ptr<ConnectionImpl> c = connectionWeak.lock();
+ if (c) {
+ channel.handle(frame);
+ c->expand(frame.encodedSize(), canBlock);
+ }
+}
+
+void SessionImpl::deliver(AMQFrame& frame) // network thread
+{
+ if (!arriving) {
+ arriving = FrameSet::shared_ptr(new FrameSet(nextIn++));
+ }
+ arriving->append(frame);
+ if (arriving->isComplete()) {
+ //message.transfers will be marked completed only when 'acked'
+ //as completion affects flow control; other commands will be
+ //considered completed as soon as processed here
+ if (arriving->isA<MessageTransferBody>()) {
+ Lock l(state);
+ incompleteIn.add(arriving->getId());
+ } else {
+ Lock l(state);
+ completedIn.add(arriving->getId());
+ }
+ demux.handle(arriving);
+ arriving.reset();
+ }
+}
+
+//control handler methods (called by network thread when controls are
+//received from peer):
+
+void SessionImpl::attach(const std::string& /*name*/, bool /*force*/)
+{
+ throw NotImplementedException("Client does not support attach");
+}
+
+void SessionImpl::attached(const std::string& _name)
+{
+ Lock l(state);
+ if (id.getName() != _name) throw InternalErrorException("Incorrect session name");
+ setState(ATTACHED);
+}
+
+void SessionImpl::detach(const std::string& _name)
+{
+ Lock l(state);
+ if (id.getName() != _name) throw InternalErrorException("Incorrect session name");
+ setState(DETACHED);
+ QPID_LOG(info, "Session detached by peer: " << id);
+}
+
+void SessionImpl::detached(const std::string& _name, uint8_t _code) {
+ Lock l(state);
+ if (id.getName() != _name) throw InternalErrorException("Incorrect session name");
+ setState(DETACHED);
+ if (_code) {
+ //TODO: make sure this works with execution.exception - don't
+ //want to overwrite the code from that
+ setExceptionLH(createChannelException(_code, "Session detached by peer"));
+ QPID_LOG(error, exceptionHolder.what());
+ }
+ if (detachedLifetime == 0) {
+ handleClosed();
+}
+}
+
+void SessionImpl::requestTimeout(uint32_t t)
+{
+ Lock l(state);
+ detachedLifetime = t;
+ proxy.timeout(t);
+}
+
+void SessionImpl::timeout(uint32_t t)
+{
+ Lock l(state);
+ detachedLifetime = t;
+}
+
+void SessionImpl::commandPoint(const framing::SequenceNumber& id, uint64_t offset)
+{
+ if (offset) throw NotImplementedException("Non-zero byte offset not yet supported for command-point");
+
+ Lock l(state);
+ nextIn = id;
+}
+
+void SessionImpl::expected(const framing::SequenceSet& commands, const framing::Array& fragments)
+{
+ if (!commands.empty() || fragments.encodedSize()) {
+ throw NotImplementedException("Session resumption not yet supported");
+ }
+}
+
+void SessionImpl::confirmed(const framing::SequenceSet& /*commands*/, const framing::Array& /*fragments*/)
+{
+ //don't really care too much about this yet
+}
+
+void SessionImpl::completed(const framing::SequenceSet& commands, bool timelyReply)
+{
+ Lock l(state);
+ incompleteOut.remove(commands);
+ state.notifyAll();//notify any waiters of completion
+ completedOut.add(commands);
+ //notify any waiting results of completion
+ results.completed(commands);
+
+ if (timelyReply) {
+ proxy.knownCompleted(completedOut);
+ completedOut.clear();
+ }
+}
+
+void SessionImpl::knownCompleted(const framing::SequenceSet& commands)
+{
+ Lock l(state);
+ completedIn.remove(commands);
+}
+
+void SessionImpl::flush(bool expected, bool confirmed, bool completed)
+{
+ Lock l(state);
+ if (expected) {
+ proxy.expected(SequenceSet(nextIn), Array());
+ }
+ if (confirmed) {
+ proxy.confirmed(completedIn, Array());
+ }
+ if (completed) {
+ proxy.completed(completedIn, true);
+ }
+}
+
+void SessionImpl::sendCompletion()
+{
+ Lock l(state);
+ sendCompletionImpl();
+}
+
+void SessionImpl::sendFlush()
+{
+ Lock l(state);
+ proxy.flush(false, false, true);
+}
+
+void SessionImpl::sendCompletionImpl()
+{
+ proxy.completed(completedIn, completedIn.span() > 1000);
+}
+
+void SessionImpl::gap(const framing::SequenceSet& /*commands*/)
+{
+ throw NotImplementedException("gap not yet supported");
+}
+
+void SessionImpl::sync() {}
+
+void SessionImpl::result(const framing::SequenceNumber& commandId, const std::string& value)
+{
+ Lock l(state);
+ results.received(commandId, value);
+}
+
+void SessionImpl::exception(uint16_t errorCode,
+ const framing::SequenceNumber& commandId,
+ uint8_t classCode,
+ uint8_t commandCode,
+ uint8_t /*fieldIndex*/,
+ const std::string& description,
+ const framing::FieldTable& /*errorInfo*/)
+{
+ Lock l(state);
+ setExceptionLH(createSessionException(errorCode, description));
+ QPID_LOG(warning, "Exception received from broker: " << exceptionHolder.what()
+ << " [caused by " << commandId << " " << classCode << ":" << commandCode << "]");
+
+ if (detachedLifetime)
+ setTimeout(0);
+}
+
+
+//private utility methods:
+
+inline void SessionImpl::setState(State s) //call with lock held
+{
+ state = s;
+}
+
+inline void SessionImpl::waitFor(State s) //call with lock held
+{
+ // We can be DETACHED at any time
+ if (s == DETACHED) state.waitFor(DETACHED);
+ else state.waitFor(States(s, DETACHED));
+ check();
+}
+
+void SessionImpl::check() const //call with lock held.
+{
+ exceptionHolder.raise();
+}
+
+void SessionImpl::checkOpen() const //call with lock held.
+{
+ check();
+ if (state != ATTACHED) {
+ throw NotAttachedException(QPID_MSG("Session " << getId() << " isn't attached"));
+ }
+}
+
+void SessionImpl::assertOpen() const
+{
+ Lock l(state);
+ checkOpen();
+}
+
+void SessionImpl::handleClosed()
+{
+ demux.close(exceptionHolder.empty() ? new ClosedException() : exceptionHolder);
+ results.close();
+}
+
+uint32_t SessionImpl::setTimeout(uint32_t seconds) {
+ proxy.requestTimeout(seconds);
+ // FIXME aconway 2008-10-07: wait for timeout response from broker
+ // and use value retured by broker.
+ detachedLifetime = seconds;
+ return detachedLifetime;
+}
+
+uint32_t SessionImpl::getTimeout() const {
+ return detachedLifetime;
+}
+
+void SessionImpl::setWeakPtr(bool weak) {
+ weakPtr = weak;
+ if (weakPtr)
+ connectionShared.reset(); // Only keep weak pointer
+ else
+ connectionShared = connectionWeak.lock();
+}
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/client/SessionImpl.h b/RC9/qpid/cpp/src/qpid/client/SessionImpl.h
new file mode 100644
index 0000000000..ea7776634a
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/SessionImpl.h
@@ -0,0 +1,219 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef _SessionImpl_
+#define _SessionImpl_
+
+#include "Demux.h"
+#include "Execution.h"
+#include "Results.h"
+
+#include "qpid/SessionId.h"
+#include "qpid/SessionState.h"
+#include "boost/shared_ptr.hpp"
+#include "boost/weak_ptr.hpp"
+#include "qpid/framing/FrameHandler.h"
+#include "qpid/framing/ChannelHandler.h"
+#include "qpid/framing/SequenceNumber.h"
+#include "qpid/framing/AMQP_ClientOperations.h"
+#include "qpid/framing/AMQP_ServerProxy.h"
+#include "qpid/sys/Semaphore.h"
+#include "qpid/sys/StateMonitor.h"
+#include "qpid/sys/ExceptionHolder.h"
+
+#include <boost/optional.hpp>
+
+namespace qpid {
+
+namespace framing {
+
+class FrameSet;
+class MethodContent;
+class SequenceSet;
+
+}
+
+namespace client {
+
+class Future;
+class ConnectionImpl;
+class SessionHandler;
+
+///@internal
+class SessionImpl : public framing::FrameHandler::InOutHandler,
+ public Execution,
+ private framing::AMQP_ClientOperations::SessionHandler,
+ private framing::AMQP_ClientOperations::ExecutionHandler
+{
+public:
+ SessionImpl(const std::string& name, shared_ptr<ConnectionImpl>);
+ ~SessionImpl();
+
+
+ //NOTE: Public functions called in user thread.
+ framing::FrameSet::shared_ptr get();
+
+ const SessionId getId() const;
+
+ uint16_t getChannel() const;
+ void setChannel(uint16_t channel);
+
+ void open(uint32_t detachedLifetime);
+ void close();
+ void resume(shared_ptr<ConnectionImpl>);
+ void suspend();
+
+ void assertOpen() const;
+
+ Future send(const framing::AMQBody& command);
+ Future send(const framing::AMQBody& command, const framing::MethodContent& content);
+ Future send(const framing::AMQBody& command, const framing::FrameSet& content);
+
+ Demux& getDemux();
+ void markCompleted(const framing::SequenceNumber& id, bool cumulative, bool notifyPeer);
+ void markCompleted(const framing::SequenceSet& ids, bool notifyPeer);
+ bool isComplete(const framing::SequenceNumber& id);
+ bool isCompleteUpTo(const framing::SequenceNumber& id);
+ void waitForCompletion(const framing::SequenceNumber& id);
+ void sendCompletion();
+ void sendFlush();
+
+ void setException(const sys::ExceptionHolder&);
+
+ //NOTE: these are called by the network thread when the connection is closed or dies
+ void connectionClosed(uint16_t code, const std::string& text);
+ void connectionBroke(const std::string& text);
+
+ /** Set timeout in seconds, returns actual timeout allowed by broker */
+ uint32_t setTimeout(uint32_t requestedSeconds);
+
+ /** Get timeout in seconds. */
+ uint32_t getTimeout() const;
+
+ /** Make this session use a weak_ptr to the ConnectionImpl.
+ * Used for sessions created by the ConnectionImpl itself.
+ */
+ void setWeakPtr(bool weak=true);
+
+private:
+ enum State {
+ INACTIVE,
+ ATTACHING,
+ ATTACHED,
+ DETACHING,
+ DETACHED
+ };
+ typedef framing::AMQP_ClientOperations::SessionHandler SessionHandler;
+ typedef framing::AMQP_ClientOperations::ExecutionHandler ExecutionHandler;
+ typedef sys::StateMonitor<State, DETACHED> StateMonitor;
+ typedef StateMonitor::Set States;
+
+ inline void setState(State s);
+ inline void waitFor(State);
+
+ void setExceptionLH(const sys::ExceptionHolder&); // LH = lock held when called.
+ void detach();
+
+ void check() const;
+ void checkOpen() const;
+ void handleClosed();
+
+ void handleIn(framing::AMQFrame& frame);
+ void handleOut(framing::AMQFrame& frame);
+ /**
+ * Sends session controls. This case is treated slightly
+ * differently than command frames sent by the application via
+ * handleOut(); session controlsare not subject to bounds checking
+ * on the outgoing frame queue.
+ */
+ void proxyOut(framing::AMQFrame& frame);
+ void sendFrame(framing::AMQFrame& frame, bool canBlock);
+ void deliver(framing::AMQFrame& frame);
+
+ Future sendCommand(const framing::AMQBody&, const framing::MethodContent* = 0);
+ void sendContent(const framing::MethodContent&);
+ void waitForCompletionImpl(const framing::SequenceNumber& id);
+
+ void sendCompletionImpl();
+
+ // Note: Following methods are called by network thread in
+ // response to session controls from the broker
+ void attach(const std::string& name, bool force);
+ void attached(const std::string& name);
+ void detach(const std::string& name);
+ void detached(const std::string& name, uint8_t detachCode);
+ void requestTimeout(uint32_t timeout);
+ void timeout(uint32_t timeout);
+ void commandPoint(const framing::SequenceNumber& commandId, uint64_t commandOffset);
+ void expected(const framing::SequenceSet& commands, const framing::Array& fragments);
+ void confirmed(const framing::SequenceSet& commands, const framing::Array& fragments);
+ void completed(const framing::SequenceSet& commands, bool timelyReply);
+ void knownCompleted(const framing::SequenceSet& commands);
+ void flush(bool expected, bool confirmed, bool completed);
+ void gap(const framing::SequenceSet& commands);
+
+ // Note: Following methods are called by network thread in
+ // response to execution commands from the broker
+ void sync();
+ void result(const framing::SequenceNumber& commandId, const std::string& value);
+ void exception(uint16_t errorCode,
+ const framing::SequenceNumber& commandId,
+ uint8_t classCode,
+ uint8_t commandCode,
+ uint8_t fieldIndex,
+ const std::string& description,
+ const framing::FieldTable& errorInfo);
+
+ sys::ExceptionHolder exceptionHolder;
+ mutable StateMonitor state;
+ mutable sys::Semaphore sendLock;
+ uint32_t detachedLifetime;
+ const uint64_t maxFrameSize;
+ const SessionId id;
+
+ shared_ptr<ConnectionImpl> connection();
+ shared_ptr<ConnectionImpl> connectionShared;
+ boost::weak_ptr<ConnectionImpl> connectionWeak;
+ bool weakPtr;
+
+ framing::FrameHandler::MemFunRef<SessionImpl, &SessionImpl::proxyOut> ioHandler;
+ framing::ChannelHandler channel;
+ framing::AMQP_ServerProxy::Session proxy;
+
+ Results results;
+ Demux demux;
+ framing::FrameSet::shared_ptr arriving;
+
+ framing::SequenceSet incompleteIn;//incoming commands that are as yet incomplete
+ framing::SequenceSet completedIn;//incoming commands that are have completed
+ framing::SequenceSet incompleteOut;//outgoing commands not yet known to be complete
+ framing::SequenceSet completedOut;//outgoing commands that we know to be completed
+ framing::SequenceNumber nextIn;
+ framing::SequenceNumber nextOut;
+
+ SessionState sessionState;
+
+ friend class client::SessionHandler;
+};
+
+}} // namespace qpid::client
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/client/SslConnector.cpp b/RC9/qpid/cpp/src/qpid/client/SslConnector.cpp
new file mode 100644
index 0000000000..6dbdbd003e
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/SslConnector.cpp
@@ -0,0 +1,399 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "Connector.h"
+
+#include "Bounds.h"
+#include "ConnectionImpl.h"
+#include "ConnectionSettings.h"
+#include "qpid/Options.h"
+#include "qpid/log/Statement.h"
+#include "qpid/sys/Time.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/sys/ssl/util.h"
+#include "qpid/sys/ssl/SslIo.h"
+#include "qpid/sys/ssl/SslSocket.h"
+#include "qpid/sys/Dispatcher.h"
+#include "qpid/sys/Poller.h"
+#include "qpid/Msg.h"
+
+#include <iostream>
+#include <map>
+#include <boost/bind.hpp>
+#include <boost/format.hpp>
+
+namespace qpid {
+namespace client {
+
+using namespace qpid::sys;
+using namespace qpid::sys::ssl;
+using namespace qpid::framing;
+using boost::format;
+using boost::str;
+
+
+class SslConnector : public Connector, private sys::Runnable
+{
+ struct Buff;
+
+ /** Batch up frames for writing to aio. */
+ class Writer : public framing::FrameHandler {
+ typedef sys::ssl::SslIOBufferBase BufferBase;
+ typedef std::vector<framing::AMQFrame> Frames;
+
+ const uint16_t maxFrameSize;
+ sys::Mutex lock;
+ sys::ssl::SslIO* aio;
+ BufferBase* buffer;
+ Frames frames;
+ size_t lastEof; // Position after last EOF in frames
+ framing::Buffer encode;
+ size_t framesEncoded;
+ std::string identifier;
+ Bounds* bounds;
+
+ void writeOne();
+ void newBuffer();
+
+ public:
+
+ Writer(uint16_t maxFrameSize, Bounds*);
+ ~Writer();
+ void init(std::string id, sys::ssl::SslIO*);
+ void handle(framing::AMQFrame&);
+ void write(sys::ssl::SslIO&);
+ };
+
+ const uint16_t maxFrameSize;
+ framing::ProtocolVersion version;
+ bool initiated;
+
+ sys::Mutex closedLock;
+ bool closed;
+ bool joined;
+
+ sys::ShutdownHandler* shutdownHandler;
+ framing::InputHandler* input;
+ framing::InitiationHandler* initialiser;
+ framing::OutputHandler* output;
+
+ Writer writer;
+
+ sys::Thread receiver;
+
+ sys::ssl::SslSocket socket;
+
+ sys::ssl::SslIO* aio;
+ boost::shared_ptr<sys::Poller> poller;
+
+ ~SslConnector();
+
+ void run();
+ void handleClosed();
+ bool closeInternal();
+
+ void readbuff(qpid::sys::ssl::SslIO&, qpid::sys::ssl::SslIOBufferBase*);
+ void writebuff(qpid::sys::ssl::SslIO&);
+ void writeDataBlock(const framing::AMQDataBlock& data);
+ void eof(qpid::sys::ssl::SslIO&);
+
+ std::string identifier;
+
+ ConnectionImpl* impl;
+
+ void connect(const std::string& host, int port);
+ void init();
+ void close();
+ void send(framing::AMQFrame& frame);
+
+ void setInputHandler(framing::InputHandler* handler);
+ void setShutdownHandler(sys::ShutdownHandler* handler);
+ sys::ShutdownHandler* getShutdownHandler() const;
+ framing::OutputHandler* getOutputHandler();
+ const std::string& getIdentifier() const;
+
+public:
+ SslConnector(framing::ProtocolVersion pVersion,
+ const ConnectionSettings&,
+ ConnectionImpl*);
+};
+
+// Static constructor which registers connector here
+namespace {
+ Connector* create(framing::ProtocolVersion v, const ConnectionSettings& s, ConnectionImpl* c) {
+ return new SslConnector(v, s, c);
+ }
+
+ struct StaticInit {
+ StaticInit() {
+ try {
+ SslOptions options;
+ options.parse (0, 0, CONF_FILE, true);
+ if (options.certDbPath.empty()) {
+ QPID_LOG(warning, "SSL connector not enabled, you must set QPID_SSL_CERT_DB to enable it.");
+ } else {
+ initNSS(options);
+ Connector::registerFactory("ssl", &create);
+ }
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Failed to initialise SSL connector: " << e.what());
+ }
+ };
+
+ ~StaticInit() { shutdownNSS(); }
+ } init;
+}
+
+SslConnector::SslConnector(ProtocolVersion ver,
+ const ConnectionSettings& settings,
+ ConnectionImpl* cimpl)
+ : maxFrameSize(settings.maxFrameSize),
+ version(ver),
+ initiated(false),
+ closed(true),
+ joined(true),
+ shutdownHandler(0),
+ writer(maxFrameSize, cimpl),
+ aio(0),
+ impl(cimpl)
+{
+ QPID_LOG(debug, "SslConnector created for " << version.toString());
+ //TODO: how do we want to handle socket configuration with ssl?
+ //settings.configureSocket(socket);
+}
+
+SslConnector::~SslConnector() {
+ close();
+}
+
+void SslConnector::connect(const std::string& host, int port){
+ Mutex::ScopedLock l(closedLock);
+ assert(closed);
+ try {
+ socket.connect(host, port);
+ } catch (const std::exception& e) {
+ socket.close();
+ throw;
+ }
+
+ identifier = str(format("[%1% %2%]") % socket.getLocalPort() % socket.getPeerAddress());
+ closed = false;
+ poller = Poller::shared_ptr(new Poller);
+ aio = new SslIO(socket,
+ boost::bind(&SslConnector::readbuff, this, _1, _2),
+ boost::bind(&SslConnector::eof, this, _1),
+ boost::bind(&SslConnector::eof, this, _1),
+ 0, // closed
+ 0, // nobuffs
+ boost::bind(&SslConnector::writebuff, this, _1));
+ writer.init(identifier, aio);
+}
+
+void SslConnector::init(){
+ Mutex::ScopedLock l(closedLock);
+ assert(joined);
+ ProtocolInitiation init(version);
+ writeDataBlock(init);
+ joined = false;
+ receiver = Thread(this);
+}
+
+bool SslConnector::closeInternal() {
+ Mutex::ScopedLock l(closedLock);
+ bool ret = !closed;
+ if (!closed) {
+ closed = true;
+ poller->shutdown();
+ }
+ if (!joined && receiver.id() != Thread::current().id()) {
+ joined = true;
+ Mutex::ScopedUnlock u(closedLock);
+ receiver.join();
+ }
+ return ret;
+}
+
+void SslConnector::close() {
+ closeInternal();
+}
+
+void SslConnector::setInputHandler(InputHandler* handler){
+ input = handler;
+}
+
+void SslConnector::setShutdownHandler(ShutdownHandler* handler){
+ shutdownHandler = handler;
+}
+
+OutputHandler* SslConnector::getOutputHandler() {
+ return this;
+}
+
+sys::ShutdownHandler* SslConnector::getShutdownHandler() const {
+ return shutdownHandler;
+}
+
+const std::string& SslConnector::getIdentifier() const {
+ return identifier;
+}
+
+void SslConnector::send(AMQFrame& frame) {
+ writer.handle(frame);
+}
+
+void SslConnector::handleClosed() {
+ if (closeInternal() && shutdownHandler)
+ shutdownHandler->shutdown();
+}
+
+struct SslConnector::Buff : public SslIO::BufferBase {
+ Buff(size_t size) : SslIO::BufferBase(new char[size], size) {}
+ ~Buff() { delete [] bytes;}
+};
+
+SslConnector::Writer::Writer(uint16_t s, Bounds* b) : maxFrameSize(s), aio(0), buffer(0), lastEof(0), bounds(b)
+{
+}
+
+SslConnector::Writer::~Writer() { delete buffer; }
+
+void SslConnector::Writer::init(std::string id, sys::ssl::SslIO* a) {
+ Mutex::ScopedLock l(lock);
+ identifier = id;
+ aio = a;
+ newBuffer();
+}
+void SslConnector::Writer::handle(framing::AMQFrame& frame) {
+ Mutex::ScopedLock l(lock);
+ frames.push_back(frame);
+ if (frame.getEof() || (bounds && bounds->getCurrentSize() >= maxFrameSize)) {
+ lastEof = frames.size();
+ aio->notifyPendingWrite();
+ }
+ QPID_LOG(trace, "SENT " << identifier << ": " << frame);
+}
+
+void SslConnector::Writer::writeOne() {
+ assert(buffer);
+ framesEncoded = 0;
+
+ buffer->dataStart = 0;
+ buffer->dataCount = encode.getPosition();
+ aio->queueWrite(buffer);
+ newBuffer();
+}
+
+void SslConnector::Writer::newBuffer() {
+ buffer = aio->getQueuedBuffer();
+ if (!buffer) buffer = new Buff(maxFrameSize);
+ encode = framing::Buffer(buffer->bytes, buffer->byteCount);
+ framesEncoded = 0;
+}
+
+// Called in IO thread.
+void SslConnector::Writer::write(sys::ssl::SslIO&) {
+ Mutex::ScopedLock l(lock);
+ assert(buffer);
+ size_t bytesWritten(0);
+ for (size_t i = 0; i < lastEof; ++i) {
+ AMQFrame& frame = frames[i];
+ uint32_t size = frame.encodedSize();
+ if (size > encode.available()) writeOne();
+ assert(size <= encode.available());
+ frame.encode(encode);
+ ++framesEncoded;
+ bytesWritten += size;
+ }
+ frames.erase(frames.begin(), frames.begin()+lastEof);
+ lastEof = 0;
+ if (bounds) bounds->reduce(bytesWritten);
+ if (encode.getPosition() > 0) writeOne();
+}
+
+void SslConnector::readbuff(SslIO& aio, SslIO::BufferBase* buff) {
+ framing::Buffer in(buff->bytes+buff->dataStart, buff->dataCount);
+
+ if (!initiated) {
+ framing::ProtocolInitiation protocolInit;
+ if (protocolInit.decode(in)) {
+ //TODO: check the version is correct
+ QPID_LOG(debug, "RECV " << identifier << " INIT(" << protocolInit << ")");
+ }
+ initiated = true;
+ }
+ AMQFrame frame;
+ while(frame.decode(in)){
+ QPID_LOG(trace, "RECV " << identifier << ": " << frame);
+ input->received(frame);
+ }
+ // TODO: unreading needs to go away, and when we can cope
+ // with multiple sub-buffers in the general buffer scheme, it will
+ if (in.available() != 0) {
+ // Adjust buffer for used bytes and then "unread them"
+ buff->dataStart += buff->dataCount-in.available();
+ buff->dataCount = in.available();
+ aio.unread(buff);
+ } else {
+ // Give whole buffer back to aio subsystem
+ aio.queueReadBuffer(buff);
+ }
+}
+
+void SslConnector::writebuff(SslIO& aio_) {
+ writer.write(aio_);
+}
+
+void SslConnector::writeDataBlock(const AMQDataBlock& data) {
+ SslIO::BufferBase* buff = new Buff(maxFrameSize);
+ framing::Buffer out(buff->bytes, buff->byteCount);
+ data.encode(out);
+ buff->dataCount = data.encodedSize();
+ aio->queueWrite(buff);
+}
+
+void SslConnector::eof(SslIO&) {
+ handleClosed();
+}
+
+// TODO: astitcher 20070908 This version of the code can never time out, so the idle processing
+// will never be called
+void SslConnector::run(){
+ // Keep the connection impl in memory until run() completes.
+ boost::shared_ptr<ConnectionImpl> protect = impl->shared_from_this();
+ assert(protect);
+ try {
+ Dispatcher d(poller);
+
+ for (int i = 0; i < 32; i++) {
+ aio->queueReadBuffer(new Buff(maxFrameSize));
+ }
+
+ aio->start(poller);
+ d.run();
+ aio->queueForDeletion();
+ socket.close();
+ } catch (const std::exception& e) {
+ QPID_LOG(error, e.what());
+ handleClosed();
+ }
+}
+
+
+}} // namespace qpid::client
diff --git a/RC9/qpid/cpp/src/qpid/client/StateManager.cpp b/RC9/qpid/cpp/src/qpid/client/StateManager.cpp
new file mode 100644
index 0000000000..0cb3c6b9d4
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/StateManager.cpp
@@ -0,0 +1,68 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "StateManager.h"
+#include "qpid/framing/amqp_framing.h"
+
+using namespace qpid::client;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+StateManager::StateManager(int s) : state(s) {}
+
+void StateManager::waitForStateChange(int current)
+{
+ Monitor::ScopedLock l(stateLock);
+ while (state == current) {
+ stateLock.wait();
+ }
+}
+
+void StateManager::waitFor(int desired)
+{
+ Monitor::ScopedLock l(stateLock);
+ while (state != desired) {
+ stateLock.wait();
+ }
+}
+
+void StateManager::waitFor(std::set<int> desired)
+{
+ Monitor::ScopedLock l(stateLock);
+ while (desired.find(state) == desired.end()) {
+ stateLock.wait();
+ }
+}
+
+
+void StateManager::setState(int s)
+{
+ Monitor::ScopedLock l(stateLock);
+ state = s;
+ stateLock.notifyAll();
+}
+
+int StateManager::getState() const
+{
+ Monitor::ScopedLock l(stateLock);
+ return state;
+}
+
diff --git a/RC9/qpid/cpp/src/qpid/client/StateManager.h b/RC9/qpid/cpp/src/qpid/client/StateManager.h
new file mode 100644
index 0000000000..b01664a0c1
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/StateManager.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _StateManager_
+#define _StateManager_
+
+#include <set>
+#include "qpid/sys/Monitor.h"
+
+namespace qpid {
+namespace client {
+
+///@internal
+class StateManager
+{
+ int state;
+ mutable sys::Monitor stateLock;
+
+public:
+ StateManager(int initial);
+ void setState(int state);
+ int getState() const ;
+ void waitForStateChange(int current);
+ void waitFor(std::set<int> states);
+ void waitFor(int state);
+};
+
+}}
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/client/Subscription.cpp b/RC9/qpid/cpp/src/qpid/client/Subscription.cpp
new file mode 100644
index 0000000000..1f1b5ac6c6
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/Subscription.cpp
@@ -0,0 +1,50 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Subscription.h"
+#include "SubscriptionImpl.h"
+#include "HandlePrivate.h"
+#include "qpid/framing/enum.h"
+
+namespace qpid {
+namespace client {
+
+template class Handle<SubscriptionImpl>;
+
+
+std::string Subscription::getName() const { return impl->getName(); }
+std::string Subscription::getQueue() const { return impl->getQueue(); }
+const SubscriptionSettings& Subscription::getSettings() const { return impl->getSettings(); }
+void Subscription::setFlowControl(const FlowControl& f) { impl->setFlowControl(f); }
+void Subscription::setAutoAck(unsigned int n) { impl->setAutoAck(n); }
+SequenceSet Subscription::getUnacquired() const { return impl->getUnacquired(); }
+SequenceSet Subscription::getUnaccepted() const { return impl->getUnaccepted(); }
+void Subscription::acquire(const SequenceSet& messageIds) { impl->acquire(messageIds); }
+void Subscription::accept(const SequenceSet& messageIds) { impl->accept(messageIds); }
+void Subscription::release(const SequenceSet& messageIds) { impl->release(messageIds); }
+Session Subscription::getSession() const { return impl->getSession(); }
+SubscriptionManager&Subscription:: getSubscriptionManager() const { return impl->getSubscriptionManager(); }
+void Subscription::cancel() { impl->cancel(); }
+void Subscription::grantMessageCredit(uint32_t value) { impl->grantCredit(framing::message::CREDIT_UNIT_MESSAGE, value); }
+void Subscription::grantByteCredit(uint32_t value) { impl->grantCredit(framing::message::CREDIT_UNIT_BYTE, value); }
+}} // namespace qpid::client
+
+
diff --git a/RC9/qpid/cpp/src/qpid/client/Subscription.h b/RC9/qpid/cpp/src/qpid/client/Subscription.h
new file mode 100644
index 0000000000..6d9342bf09
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/Subscription.h
@@ -0,0 +1,113 @@
+#ifndef QPID_CLIENT_SUBSCRIPTION_H
+#define QPID_CLIENT_SUBSCRIPTION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/client/Session.h"
+#include "qpid/client/SubscriptionSettings.h"
+#include "qpid/client/Handle.h"
+#include "qpid/client/Message.h"
+
+namespace qpid {
+namespace client {
+
+class SubscriptionImpl;
+class SubscriptionManager;
+
+/**
+ * A handle to an active subscription. Provides methods to query the subscription status
+ * and control acknowledgement (acquire and accept) of messages.
+ */
+class Subscription : public Handle<SubscriptionImpl> {
+ public:
+ Subscription(SubscriptionImpl* si=0) : Handle<SubscriptionImpl>(si) {}
+
+ /** The name of the subsctription, used as the "destination" for messages from the broker.
+ * Usually the same as the queue name but can be set differently.
+ */
+ std::string getName() const;
+
+ /** Name of the queue this subscription subscribes to */
+ std::string getQueue() const;
+
+ /** Get the flow control and acknowledgement settings for this subscription */
+ const SubscriptionSettings& getSettings() const;
+
+ /** Set the flow control parameters */
+ void setFlowControl(const FlowControl&);
+
+ /** Automatically acknowledge (acquire and accept) batches of n messages.
+ * You can disable auto-acknowledgement by setting n=0, and use acquire() and accept()
+ * to manually acquire and accept messages.
+ */
+ void setAutoAck(unsigned int n);
+
+ /** Get the set of ID's for messages received by this subscription but not yet acquired.
+ * This will always be empty if getSettings().acquireMode=ACQUIRE_MODE_PRE_ACQUIRED
+ */
+ SequenceSet getUnacquired() const;
+
+ /** Get the set of ID's for messages received by this subscription but not yet accepted. */
+ SequenceSet getUnaccepted() const;
+
+ /** Acquire messageIds and remove them from the unacquired set.
+ * oAdd them to the unaccepted set if getSettings().acceptMode == ACCEPT_MODE_EXPLICIT.
+ */
+ void acquire(const SequenceSet& messageIds);
+
+ /** Accept messageIds and remove them from the unaccepted set.
+ *@pre messageIds is a subset of getUnaccepted()
+ */
+ void accept(const SequenceSet& messageIds);
+
+ /** Release messageIds and remove them from the unaccepted set.
+ *@pre messageIds is a subset of getUnaccepted()
+ */
+ void release(const SequenceSet& messageIds);
+
+ /* Acquire a single message */
+ void acquire(const Message& m) { acquire(SequenceSet(m.getId())); }
+
+ /* Accept a single message */
+ void accept(const Message& m) { accept(SequenceSet(m.getId())); }
+
+ /* Release a single message */
+ void release(const Message& m) { release(SequenceSet(m.getId())); }
+
+ /** Get the session associated with this subscription */
+ Session getSession() const;
+
+ /** Get the subscription manager associated with this subscription */
+ SubscriptionManager& getSubscriptionManager() const;
+
+ /** Cancel the subscription. */
+ void cancel();
+
+ /** Grant the specified amount of message credit */
+ void grantMessageCredit(uint32_t);
+
+ /** Grant the specified amount of byte credit */
+ void grantByteCredit(uint32_t);
+};
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_SUBSCRIPTION_H*/
diff --git a/RC9/qpid/cpp/src/qpid/client/SubscriptionImpl.cpp b/RC9/qpid/cpp/src/qpid/client/SubscriptionImpl.cpp
new file mode 100644
index 0000000000..5ea87110c2
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/SubscriptionImpl.cpp
@@ -0,0 +1,149 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "SubscriptionImpl.h"
+#include "SubscriptionManager.h"
+#include "SubscriptionSettings.h"
+
+namespace qpid {
+namespace client {
+
+using sys::Mutex;
+using framing::MessageAcquireResult;
+
+SubscriptionImpl::SubscriptionImpl(SubscriptionManager& m, const std::string& q, const SubscriptionSettings& s, const std::string& n, MessageListener* l)
+ : manager(m), name(n), queue(q), settings(s), listener(l)
+{}
+
+void SubscriptionImpl::subscribe()
+{
+ async(manager.getSession()).messageSubscribe(
+ arg::queue=queue,
+ arg::destination=name,
+ arg::acceptMode=settings.acceptMode,
+ arg::acquireMode=settings.acquireMode,
+ arg::exclusive=settings.exclusive);
+ setFlowControl(settings.flowControl);
+}
+
+std::string SubscriptionImpl::getName() const { return name; }
+
+std::string SubscriptionImpl::getQueue() const { return queue; }
+
+const SubscriptionSettings& SubscriptionImpl::getSettings() const {
+ Mutex::ScopedLock l(lock);
+ return settings;
+}
+
+void SubscriptionImpl::setFlowControl(const FlowControl& f) {
+ Mutex::ScopedLock l(lock);
+ AsyncSession s=manager.getSession();
+ if (&settings.flowControl != &f) settings.flowControl = f;
+ s.messageSetFlowMode(name, f.window);
+ s.messageFlow(name, CREDIT_UNIT_MESSAGE, f.messages);
+ s.messageFlow(name, CREDIT_UNIT_BYTE, f.bytes);
+ s.sync();
+}
+
+void SubscriptionImpl::grantCredit(framing::message::CreditUnit unit, uint32_t value) {
+ async(manager.getSession()).messageFlow(name, unit, value);
+}
+
+void SubscriptionImpl::setAutoAck(size_t n) {
+ Mutex::ScopedLock l(lock);
+ settings.autoAck = n;
+}
+
+SequenceSet SubscriptionImpl::getUnacquired() const { Mutex::ScopedLock l(lock); return unacquired; }
+SequenceSet SubscriptionImpl::getUnaccepted() const { Mutex::ScopedLock l(lock); return unaccepted; }
+
+void SubscriptionImpl::acquire(const SequenceSet& messageIds) {
+ Mutex::ScopedLock l(lock);
+ MessageAcquireResult result = manager.getSession().messageAcquire(messageIds);
+ unacquired.remove(result.getTransfers());
+ if (settings.acceptMode == ACCEPT_MODE_EXPLICIT)
+ unaccepted.add(result.getTransfers());
+}
+
+void SubscriptionImpl::accept(const SequenceSet& messageIds) {
+ Mutex::ScopedLock l(lock);
+ manager.getSession().messageAccept(messageIds);
+ unaccepted.remove(messageIds);
+ switch (settings.completionMode) {
+ case COMPLETE_ON_ACCEPT:
+ manager.getSession().markCompleted(messageIds, true);
+ break;
+ case COMPLETE_ON_DELIVERY:
+ manager.getSession().sendCompletion();
+ break;
+ default://do nothing
+ break;
+ }
+}
+
+void SubscriptionImpl::release(const SequenceSet& messageIds) {
+ Mutex::ScopedLock l(lock);
+ manager.getSession().messageRelease(messageIds);
+ if (settings.acceptMode == ACCEPT_MODE_EXPLICIT)
+ unaccepted.remove(messageIds);
+}
+
+Session SubscriptionImpl::getSession() const { return manager.getSession(); }
+
+SubscriptionManager& SubscriptionImpl::getSubscriptionManager() const { return manager; }
+
+void SubscriptionImpl::cancel() { manager.cancel(name); }
+
+void SubscriptionImpl::received(Message& m) {
+ Mutex::ScopedLock l(lock);
+ if (m.getMethod().getAcquireMode() == ACQUIRE_MODE_NOT_ACQUIRED)
+ unacquired.add(m.getId());
+ else if (m.getMethod().getAcceptMode() == ACCEPT_MODE_EXPLICIT)
+ unaccepted.add(m.getId());
+
+ if (listener) {
+ Mutex::ScopedUnlock u(lock);
+ listener->received(m);
+ }
+
+ if (settings.completionMode == COMPLETE_ON_DELIVERY) {
+ manager.getSession().markCompleted(m.getId(), false, false);
+ }
+ if (settings.autoAck) {
+ if (unaccepted.size() >= settings.autoAck) {
+ async(manager.getSession()).messageAccept(unaccepted);
+ switch (settings.completionMode) {
+ case COMPLETE_ON_ACCEPT:
+ manager.getSession().markCompleted(unaccepted, true);
+ break;
+ case COMPLETE_ON_DELIVERY:
+ manager.getSession().sendCompletion();
+ break;
+ default://do nothing
+ break;
+ }
+ unaccepted.clear();
+ }
+ }
+}
+
+}} // namespace qpid::client
+
diff --git a/RC9/qpid/cpp/src/qpid/client/SubscriptionImpl.h b/RC9/qpid/cpp/src/qpid/client/SubscriptionImpl.h
new file mode 100644
index 0000000000..c4c486daeb
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/SubscriptionImpl.h
@@ -0,0 +1,109 @@
+#ifndef QPID_CLIENT_SUBSCRIPTIONIMPL_H
+#define QPID_CLIENT_SUBSCRIPTIONIMPL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/client/SubscriptionSettings.h"
+#include "qpid/client/Session.h"
+#include "qpid/client/MessageListener.h"
+#include "qpid/framing/enum.h"
+#include "qpid/framing/SequenceSet.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/RefCounted.h"
+
+namespace qpid {
+namespace client {
+
+class SubscriptionManager;
+
+class SubscriptionImpl : public RefCounted, public MessageListener {
+ public:
+ SubscriptionImpl(SubscriptionManager&, const std::string& queue,
+ const SubscriptionSettings&, const std::string& name, MessageListener* =0);
+
+ /** The name of the subsctription, used as the "destination" for messages from the broker.
+ * Usually the same as the queue name but can be set differently.
+ */
+ std::string getName() const;
+
+ /** Name of the queue this subscription subscribes to */
+ std::string getQueue() const;
+
+ /** Get the flow control and acknowledgement settings for this subscription */
+ const SubscriptionSettings& getSettings() const;
+
+ /** Set the flow control parameters */
+ void setFlowControl(const FlowControl&);
+
+ /** Automatically acknowledge (acquire and accept) batches of n messages.
+ * You can disable auto-acknowledgement by setting n=0, and use acquire() and accept()
+ * to manually acquire and accept messages.
+ */
+ void setAutoAck(size_t n);
+
+ /** Get the set of ID's for messages received by this subscription but not yet acquired.
+ * This will always be empty if acquireMode=ACQUIRE_MODE_PRE_ACQUIRED
+ */
+ SequenceSet getUnacquired() const;
+
+ /** Get the set of ID's for messages acquired by this subscription but not yet accepted. */
+ SequenceSet getUnaccepted() const;
+
+ /** Acquire messageIds and remove them from the un-acquired set for the session. */
+ void acquire(const SequenceSet& messageIds);
+
+ /** Accept messageIds and remove them from the un-accepted set for the session. */
+ void accept(const SequenceSet& messageIds);
+
+ /** Release messageIds and remove them from the un-accepted set for the session. */
+ void release(const SequenceSet& messageIds);
+
+ /** Get the session associated with this subscription */
+ Session getSession() const;
+
+ /** Get the subscription manager associated with this subscription */
+ SubscriptionManager& getSubscriptionManager() const;
+
+ /** Send subscription request and issue appropriate flow control commands. */
+ void subscribe();
+
+ /** Cancel the subscription. */
+ void cancel();
+
+ /** Grant specified credit for this subscription **/
+ void grantCredit(framing::message::CreditUnit unit, uint32_t value);
+
+ void received(Message&);
+
+ private:
+
+ mutable sys::Mutex lock;
+ SubscriptionManager& manager;
+ std::string name, queue;
+ SubscriptionSettings settings;
+ framing::SequenceSet unacquired, unaccepted;
+ MessageListener* listener;
+};
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_SUBSCRIPTIONIMPL_H*/
diff --git a/RC9/qpid/cpp/src/qpid/client/SubscriptionManager.cpp b/RC9/qpid/cpp/src/qpid/client/SubscriptionManager.cpp
new file mode 100644
index 0000000000..c91ae178ac
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/SubscriptionManager.cpp
@@ -0,0 +1,140 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _Subscription_
+#define _Subscription_
+
+#include "SubscriptionManager.h"
+#include "SubscriptionImpl.h"
+#include <qpid/client/Dispatcher.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/MessageListener.h>
+#include <qpid/framing/Uuid.h>
+#include <set>
+#include <sstream>
+
+
+namespace qpid {
+namespace client {
+
+SubscriptionManager::SubscriptionManager(const Session& s)
+ : dispatcher(s), session(s), autoStop(true)
+{}
+
+Subscription SubscriptionManager::subscribe(
+ MessageListener& listener, const std::string& q, const SubscriptionSettings& ss, const std::string& n)
+{
+ std::string name=n.empty() ? q:n;
+ boost::intrusive_ptr<SubscriptionImpl> si = new SubscriptionImpl(*this, q, ss, name, &listener);
+ dispatcher.listen(si);
+ //issue subscription request after listener is registered with dispatcher
+ si->subscribe();
+ return subscriptions[name] = Subscription(si.get());
+}
+
+Subscription SubscriptionManager::subscribe(
+ LocalQueue& lq, const std::string& q, const SubscriptionSettings& ss, const std::string& n)
+{
+ std::string name=n.empty() ? q:n;
+ lq.queue=session.getExecution().getDemux().add(name, ByTransferDest(name));
+ boost::intrusive_ptr<SubscriptionImpl> si = new SubscriptionImpl(*this, q, ss, name, 0);
+ si->subscribe();
+ lq.subscription = Subscription(si.get());
+ return subscriptions[name] = lq.subscription;
+}
+
+Subscription SubscriptionManager::subscribe(
+ MessageListener& listener, const std::string& q, const std::string& n)
+{
+ return subscribe(listener, q, defaultSettings, n);
+}
+
+Subscription SubscriptionManager::subscribe(
+ LocalQueue& lq, const std::string& q, const std::string& n)
+{
+ return subscribe(lq, q, defaultSettings, n);
+}
+
+void SubscriptionManager::cancel(const std::string& dest)
+{
+ sync(session).messageCancel(dest);
+ dispatcher.cancel(dest);
+}
+
+void SubscriptionManager::setAutoStop(bool set) { autoStop=set; }
+
+void SubscriptionManager::run()
+{
+ dispatcher.setAutoStop(autoStop);
+ dispatcher.run();
+}
+
+void SubscriptionManager::start()
+{
+ dispatcher.setAutoStop(autoStop);
+ dispatcher.start();
+}
+
+void SubscriptionManager::wait()
+{
+ dispatcher.wait();
+}
+
+void SubscriptionManager::stop()
+{
+ dispatcher.stop();
+}
+
+bool SubscriptionManager::get(Message& result, const std::string& queue, sys::Duration timeout) {
+ LocalQueue lq;
+ std::string unique = framing::Uuid(true).str();
+ subscribe(lq, queue, SubscriptionSettings(FlowControl::messageCredit(1)), unique);
+ AutoCancel ac(*this, unique);
+ //first wait for message to be delivered if a timeout has been specified
+ if (timeout && lq.get(result, timeout))
+ return true;
+ //make sure message is not on queue before final check
+ sync(session).messageFlush(unique);
+ return lq.get(result, 0);
+}
+
+Message SubscriptionManager::get(const std::string& queue, sys::Duration timeout) {
+ Message result;
+ if (!get(result, queue, timeout))
+ throw Exception("Timed out waiting for a message");
+ return result;
+}
+
+Session SubscriptionManager::getSession() const { return session; }
+
+Subscription SubscriptionManager::getSubscription(const std::string& name) const {
+ std::map<std::string, Subscription>::const_iterator i = subscriptions.find(name);
+ if (i == subscriptions.end())
+ throw Exception(QPID_MSG("Subscription not found: " << name));
+ return i->second;
+}
+
+void SubscriptionManager::registerFailoverHandler (boost::function<void ()> fh) {
+ dispatcher.registerFailoverHandler(fh);
+}
+
+}} // namespace qpid::client
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/client/SubscriptionManager.h b/RC9/qpid/cpp/src/qpid/client/SubscriptionManager.h
new file mode 100644
index 0000000000..1017480257
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/SubscriptionManager.h
@@ -0,0 +1,293 @@
+#ifndef QPID_CLIENT_SUBSCRIPTIONMANAGER_H
+#define QPID_CLIENT_SUBSCRIPTIONMANAGER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/sys/Mutex.h"
+#include <qpid/client/Dispatcher.h>
+#include <qpid/client/Completion.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/AsyncSession.h>
+#include <qpid/client/MessageListener.h>
+#include <qpid/client/LocalQueue.h>
+#include <qpid/client/Subscription.h>
+#include <qpid/sys/Runnable.h>
+#include <set>
+#include <sstream>
+
+namespace qpid {
+namespace client {
+
+/**
+ * A class to help create and manage subscriptions.
+ *
+ * Set up your subscriptions, then call run() to have messages
+ * delivered.
+ *
+ * \ingroup clientapi
+ *
+ * \details
+ *
+ * <h2>Subscribing and canceling subscriptions</h2>
+ *
+ * <ul>
+ * <li>
+ * <p>subscribe()</p>
+ * <pre> SubscriptionManager subscriptions(session);
+ * Listener listener(subscriptions);
+ * subscriptions.subscribe(listener, myQueue);</pre>
+ * <pre> SubscriptionManager subscriptions(session);
+ * LocalQueue local_queue;
+ * subscriptions.subscribe(local_queue, string("message_queue"));</pre></li>
+ * <li>
+ * <p>cancel()</p>
+ * <pre>subscriptions.cancel();</pre></li>
+ * </ul>
+ *
+ * <h2>Waiting for messages (and returning)</h2>
+ *
+ * <ul>
+ * <li>
+ * <p>run()</p>
+ * <pre> // Give up control to receive messages
+ * subscriptions.run();</pre></li>
+ * <li>
+ * <p>stop()</p>
+ * <pre>.// Use this code in a listener to return from run()
+ * subscriptions.stop();</pre></li>
+ * <li>
+ * <p>setAutoStop()</p>
+ * <pre>.// Return from subscriptions.run() when last subscription is cancelled
+ *.subscriptions.setAutoStop(true);
+ *.subscriptons.run();
+ * </pre></li>
+ * <li>
+ * <p>Ending a subscription in a listener</p>
+ * <pre>
+ * void Listener::received(Message&amp; message) {
+ *
+ * if (message.getData() == "That's all, folks!") {
+ * subscriptions.cancel(message.getDestination());
+ * }
+ * }
+ * </pre>
+ * </li>
+ * </ul>
+ *
+ */
+class SubscriptionManager : public sys::Runnable
+{
+ typedef sys::Mutex::ScopedLock Lock;
+ typedef sys::Mutex::ScopedUnlock Unlock;
+
+ qpid::client::Dispatcher dispatcher;
+ qpid::client::AsyncSession session;
+ bool autoStop;
+ SubscriptionSettings defaultSettings;
+
+ public:
+ /** Create a new SubscriptionManager associated with a session */
+ SubscriptionManager(const Session& session);
+
+ /**
+ * Subscribe a MessagesListener to receive messages from queue.
+ *
+ * Provide your own subclass of MessagesListener to process
+ * incoming messages. It will be called for each message received.
+ *
+ *@param listener Listener object to receive messages.
+ *@param queue Name of the queue to subscribe to.
+ *@param settings settings for the subscription.
+ *@param name unique destination name for the subscription, defaults to queue name.
+ */
+ Subscription subscribe(MessageListener& listener,
+ const std::string& queue,
+ const SubscriptionSettings& settings,
+ const std::string& name=std::string());
+
+ /**
+ * Subscribe a LocalQueue to receive messages from queue.
+ *
+ * Incoming messages are stored in the queue for you to retrieve.
+ *
+ *@param queue Name of the queue to subscribe to.
+ *@param flow initial FlowControl for the subscription.
+ *@param name unique destination name for the subscription, defaults to queue name.
+ * If not specified, the queue name is used.
+ */
+ Subscription subscribe(LocalQueue& localQueue,
+ const std::string& queue,
+ const SubscriptionSettings& settings,
+ const std::string& name=std::string());
+
+ /**
+ * Subscribe a MessagesListener to receive messages from queue.
+ *
+ * Provide your own subclass of MessagesListener to process
+ * incoming messages. It will be called for each message received.
+ *
+ *@param listener Listener object to receive messages.
+ *@param queue Name of the queue to subscribe to.
+ *@param name unique destination name for the subscription, defaults to queue name.
+ * If not specified, the queue name is used.
+ */
+ Subscription subscribe(MessageListener& listener,
+ const std::string& queue,
+ const std::string& name=std::string());
+
+ /**
+ * Subscribe a LocalQueue to receive messages from queue.
+ *
+ * Incoming messages are stored in the queue for you to retrieve.
+ *
+ *@param queue Name of the queue to subscribe to.
+ *@param name unique destination name for the subscription, defaults to queue name.
+ * If not specified, the queue name is used.
+ */
+ Subscription subscribe(LocalQueue& localQueue,
+ const std::string& queue,
+ const std::string& name=std::string());
+
+
+ /** Get a single message from a queue.
+ *@param result is set to the message from the queue.
+ *@param timeout wait up this timeout for a message to appear.
+ *@return true if result was set, false if no message available after timeout.
+ */
+ bool get(Message& result, const std::string& queue, sys::Duration timeout=0);
+
+ /** Get a single message from a queue.
+ *@param timeout wait up this timeout for a message to appear.
+ *@return message from the queue.
+ *@throw Exception if the timeout is exceeded.
+ */
+ Message get(const std::string& queue, sys::Duration timeout=sys::TIME_INFINITE);
+
+ /** Get a subscription by name.
+ *@throw Exception if not found.
+ */
+ Subscription getSubscription(const std::string& name) const;
+
+ /** Cancel a subscription. See also: Subscription.cancel() */
+ void cancel(const std::string& name);
+
+ /** Deliver messages in the current thread until stop() is called.
+ * Only one thread may be running in a SubscriptionManager at a time.
+ * @see run
+ */
+ void run();
+
+ /** Start a new thread to deliver messages.
+ * Only one thread may be running in a SubscriptionManager at a time.
+ * @see start
+ */
+ void start();
+
+ /**
+ * Wait for the thread started by a call to start() to complete.
+ */
+ void wait();
+
+ /** If set true, run() will stop when all subscriptions
+ * are cancelled. If false, run will only stop when stop()
+ * is called. True by default.
+ */
+ void setAutoStop(bool set=true);
+
+ /** Stop delivery. Causes run() to return, or the thread started with start() to exit. */
+ void stop();
+
+ static const uint32_t UNLIMITED=0xFFFFFFFF;
+
+ /** Set the flow control for a subscription. */
+ void setFlowControl(const std::string& name, const FlowControl& flow) {
+ getSubscription(name).setFlowControl(flow);
+ }
+
+ /** Set the flow control for a subscription.
+ *@param name: name of the subscription.
+ *@param messages: message credit.
+ *@param bytes: byte credit.
+ *@param window: if true use window-based flow control.
+ */
+ void setFlowControl(const std::string& name, uint32_t messages, uint32_t bytes, bool window=true) {
+ setFlowControl(name, messages, bytes, window);
+ }
+
+ /** Set the default settings for subscribe() calls that don't
+ * include a SubscriptionSettings parameter.
+ */
+ void setDefaultSettings(const SubscriptionSettings& s) { defaultSettings = s; }
+
+ /** Get the default settings for subscribe() calls that don't
+ * include a SubscriptionSettings parameter.
+ */
+ const SubscriptionSettings& getDefaultSettings() const { return defaultSettings; }
+
+ /** Get the default settings for subscribe() calls that don't
+ * include a SubscriptionSettings parameter.
+ */
+ SubscriptionSettings& getDefaultSettings() { return defaultSettings; }
+
+ /**
+ * Set the default flow control settings for subscribe() calls
+ * that don't include a SubscriptionSettings parameter.
+ *
+ *@param messages: message credit.
+ *@param bytes: byte credit.
+ *@param window: if true use window-based flow control.
+ */
+ void setFlowControl(uint32_t messages, uint32_t bytes, bool window=true) {
+ defaultSettings.flowControl = FlowControl(messages, bytes, window);
+ }
+
+ /**
+ *Set the default accept-mode for subscribe() calls that don't
+ *include a SubscriptionSettings parameter.
+ */
+ void setAcceptMode(AcceptMode mode) { defaultSettings.acceptMode = mode; }
+
+ /**
+ * Set the default acquire-mode subscribe()s that don't specify SubscriptionSettings.
+ */
+ void setAcquireMode(AcquireMode mode) { defaultSettings.acquireMode = mode; }
+
+ void registerFailoverHandler ( boost::function<void ()> fh );
+
+ Session getSession() const;
+
+ private:
+ std::map<std::string, Subscription> subscriptions;
+};
+
+/** AutoCancel cancels a subscription in its destructor */
+class AutoCancel {
+ public:
+ AutoCancel(SubscriptionManager& sm_, const std::string& tag_) : sm(sm_), tag(tag_) {}
+ ~AutoCancel() { sm.cancel(tag); }
+ private:
+ SubscriptionManager& sm;
+ std::string tag;
+};
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_SUBSCRIPTIONMANAGER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/client/SubscriptionSettings.h b/RC9/qpid/cpp/src/qpid/client/SubscriptionSettings.h
new file mode 100644
index 0000000000..ade539b376
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/SubscriptionSettings.h
@@ -0,0 +1,92 @@
+#ifndef QPID_CLIENT_SUBSCRIPTIONSETTINGS_H
+#define QPID_CLIENT_SUBSCRIPTIONSETTINGS_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/client/FlowControl.h"
+#include "qpid/framing/enum.h"
+
+namespace qpid {
+namespace client {
+
+/** Bring AMQP enum definitions for message class into this namespace. */
+using namespace qpid::framing::message;
+
+enum CompletionMode {
+ MANUAL_COMPLETION = 0,
+ COMPLETE_ON_DELIVERY = 1,
+ COMPLETE_ON_ACCEPT = 2
+};
+/**
+ * Settings for a subscription.
+ */
+struct SubscriptionSettings
+{
+ SubscriptionSettings(
+ FlowControl flow=FlowControl::unlimited(),
+ AcceptMode accept=ACCEPT_MODE_EXPLICIT,
+ AcquireMode acquire=ACQUIRE_MODE_PRE_ACQUIRED,
+ unsigned int autoAck_=1,
+ CompletionMode completion=COMPLETE_ON_DELIVERY
+ ) : flowControl(flow), acceptMode(accept), acquireMode(acquire), autoAck(autoAck_), completionMode(completion), exclusive(false) {}
+
+ FlowControl flowControl; ///@< Flow control settings. @see FlowControl
+ AcceptMode acceptMode; ///@< ACCEPT_MODE_EXPLICIT or ACCEPT_MODE_NONE
+ AcquireMode acquireMode; ///@< ACQUIRE_MODE_PRE_ACQUIRED or ACQUIRE_MODE_NOT_ACQUIRED
+
+ /** Automatically acknowledge (accept) batches of autoAck
+ * messages. 0 means no automatic acknowledgement. This has no
+ * effect for messsages received for a subscription with
+ * ACCEPT_MODE_NODE.*/
+ unsigned int autoAck;
+ /**
+ * In windowing mode, completion of a message will cause the
+ * credit used up by that message to be reallocated. The
+ * subscriptions completion mode controls how completion is
+ * managed.
+ *
+ * If set to COMPLETE_ON_DELIVERY (which is the default), messages
+ * will be marked as completed once they have been received. The
+ * server will be explicitly notified of all completed messages
+ * for the session when the next accept is sent through the
+ * subscription (either explictly or through autAck). However the
+ * server may also periodically request information on the
+ * completed messages.
+ *
+ * If set to COMPLETE_ON_ACCEPT, messages will be marked as
+ * completed once they are accepted (via the Subscription class)
+ * and the server will also be notified of all completed messages
+ * for the session.
+ *
+ * If set to MANUAL_COMPLETION the application is responsible for
+ * completing messages (@see Session::markCompleted()).
+ */
+ CompletionMode completionMode;
+ /**
+ * If set, requests that no other subscriber be allowed to access
+ * the queue while this subscription is active.
+ */
+ bool exclusive;
+};
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_SUBSCRIPTIONSETTINGS_H*/
diff --git a/RC9/qpid/cpp/src/qpid/client/TypedResult.h b/RC9/qpid/cpp/src/qpid/client/TypedResult.h
new file mode 100644
index 0000000000..5306997d74
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/client/TypedResult.h
@@ -0,0 +1,65 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef _TypedResult_
+#define _TypedResult_
+
+#include "Completion.h"
+
+namespace qpid {
+namespace client {
+
+/**
+ * Returned by asynchronous commands that return a result.
+ * You can use get() to wait for completion and get the result value.
+ * \ingroup clientapi
+ */
+template <class T> class TypedResult : public Completion
+{
+ T result;
+ bool decoded;
+
+public:
+ ///@internal
+ TypedResult(Future f, shared_ptr<SessionImpl> s) : Completion(f, s), decoded(false) {}
+
+ /**
+ * Wait for the asynchronous command that returned this TypedResult to complete
+ * and return its result.
+ *
+ *@return The result returned by the command.
+ *@exception If the command returns an error, get() throws an exception.
+ *
+ */
+ T& get()
+ {
+ if (!decoded) {
+ future.decodeResult(result, *session);
+ decoded = true;
+ }
+
+ return result;
+ }
+};
+
+}}
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/cluster/Cluster.cpp b/RC9/qpid/cpp/src/qpid/cluster/Cluster.cpp
new file mode 100644
index 0000000000..dd9de68bf5
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/Cluster.cpp
@@ -0,0 +1,548 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "Cluster.h"
+#include "Connection.h"
+#include "DumpClient.h"
+#include "FailoverExchange.h"
+
+#include "qpid/broker/Broker.h"
+#include "qpid/broker/SessionState.h"
+#include "qpid/broker/Connection.h"
+#include "qpid/broker/QueueRegistry.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/AMQP_AllOperations.h"
+#include "qpid/framing/AllInvoker.h"
+#include "qpid/framing/ClusterDumpRequestBody.h"
+#include "qpid/framing/ClusterReadyBody.h"
+#include "qpid/framing/ClusterConfigChangeBody.h"
+#include "qpid/framing/ClusterDumpOfferBody.h"
+#include "qpid/framing/ClusterShutdownBody.h"
+#include "qpid/framing/ClusterConnectionDeliverCloseBody.h"
+#include "qpid/framing/ClusterConnectionDeliverDoOutputBody.h"
+#include "qpid/log/Statement.h"
+#include "qpid/log/Helpers.h"
+#include "qpid/sys/Thread.h"
+#include "qpid/memory.h"
+#include "qpid/shared_ptr.h"
+#include "qmf/org/apache/qpid/cluster/Package.h"
+
+#include <boost/bind.hpp>
+#include <boost/cast.hpp>
+#include <boost/current_function.hpp>
+#include <algorithm>
+#include <iterator>
+#include <map>
+#include <ostream>
+
+namespace qpid {
+namespace cluster {
+using namespace qpid::framing;
+using namespace qpid::sys;
+using namespace std;
+using namespace qpid::cluster;
+using qpid::management::ManagementAgent;
+using qpid::management::ManagementObject;
+using qpid::management::Manageable;
+using qpid::management::Args;
+namespace qmf = qmf::org::apache::qpid::cluster;
+
+/**@file
+ Threading notes:
+ - Public functions may be called in local connection IO threads.
+ see .h.
+*/
+
+struct ClusterDispatcher : public framing::AMQP_AllOperations::ClusterHandler {
+ qpid::cluster::Cluster& cluster;
+ MemberId member;
+ Cluster::Lock& l;
+ ClusterDispatcher(Cluster& c, const MemberId& id, Cluster::Lock& l_) : cluster(c), member(id), l(l_) {}
+
+ void dumpRequest(const std::string& url) { cluster.dumpRequest(member, url, l); }
+ void ready(const std::string& url) { cluster.ready(member, url, l); }
+ void configChange(const std::string& addresses) { cluster.configChange(member, addresses, l); }
+ void dumpOffer(uint64_t dumpee, const Uuid& id) { cluster.dumpOffer(member, dumpee, id, l); }
+ void shutdown() { cluster.shutdown(member, l); }
+
+ bool invoke(AMQBody& body) { return framing::invoke(*this, body).wasHandled(); }
+};
+
+Cluster::Cluster(const std::string& name_, const Url& url_, broker::Broker& b, bool quorum_, size_t readMax_, size_t writeEstimate_) :
+ broker(b),
+ poller(b.getPoller()),
+ cpg(*this),
+ name(name_),
+ myUrl(url_),
+ myId(cpg.self()),
+ readMax(readMax_),
+ writeEstimate(writeEstimate_),
+ cpgDispatchHandle(
+ cpg,
+ boost::bind(&Cluster::dispatch, this, _1), // read
+ 0, // write
+ boost::bind(&Cluster::disconnect, this, _1) // disconnect
+ ),
+ mcast(cpg, poller),
+ mgmtObject(0),
+ deliverQueue(boost::bind(&Cluster::delivered, this, _1), poller),
+ state(INIT),
+ lastSize(0),
+ lastBroker(false)
+{
+ ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+ if (agent != 0){
+ qmf::Package packageInit(agent);
+ mgmtObject = new qmf::Cluster (agent, this, &broker,name,myUrl.str());
+ agent->addObject (mgmtObject);
+ mgmtObject->set_status("JOINING");
+ }
+ broker.getKnownBrokers = boost::bind(&Cluster::getUrls, this);
+ failoverExchange.reset(new FailoverExchange(this));
+ cpgDispatchHandle.startWatch(poller);
+ deliverQueue.start();
+ QPID_LOG(notice, *this << " joining cluster " << name << " with url=" << myUrl);
+ if (quorum_) quorum.init();
+ cpg.join(name);
+ broker.addFinalizer(boost::bind(&Cluster::brokerShutdown, this)); // Must be last for exception safety.
+}
+
+Cluster::~Cluster() {
+ if (dumpThread.id()) dumpThread.join(); // Join the previous dumpthread.
+}
+
+void Cluster::insert(const boost::intrusive_ptr<Connection>& c) {
+ connections.insert(c->getId(), c);
+}
+
+void Cluster::erase(ConnectionId id) {
+ connections.erase(id);
+}
+
+std::vector<Url> Cluster::getUrls() const {
+ Lock l(lock);
+ return getUrls(l);
+}
+
+std::vector<Url> Cluster::getUrls(Lock&) const {
+ return map.memberUrls();
+}
+
+void Cluster::leave() {
+ Lock l(lock);
+ leave(l);
+}
+
+void Cluster::leave(Lock&) {
+ if (state != LEFT) {
+ state = LEFT;
+ QPID_LOG(notice, *this << " leaving cluster " << name);
+ if (mgmtObject!=0) mgmtObject->set_status("SHUTDOWN");
+ if (!deliverQueue.isStopped()) deliverQueue.stop();
+ try { cpg.leave(); }
+ catch (const std::exception& e) {
+ QPID_LOG(critical, *this << " error leaving process group: " << e.what());
+ }
+ try { broker.shutdown(); }
+ catch (const std::exception& e) {
+ QPID_LOG(critical, *this << " error during shutdown: " << e.what());
+ }
+ }
+}
+
+boost::intrusive_ptr<Connection> Cluster::getConnection(const ConnectionId& connectionId) {
+ boost::intrusive_ptr<Connection> cp = connections.find(connectionId);
+ if (!cp && connectionId.getMember() != myId) { // New shadow connection
+ std::ostringstream mgmtId;
+ mgmtId << name << ":" << connectionId;
+ cp = new Connection(*this, shadowOut, mgmtId.str(), connectionId);
+ connections.insert(connectionId, cp);
+ }
+ return cp;
+}
+
+void Cluster::deliver(
+ cpg_handle_t /*handle*/,
+ cpg_name* /*group*/,
+ uint32_t nodeid,
+ uint32_t pid,
+ void* msg,
+ int msg_len)
+{
+ Mutex::ScopedLock l(lock);
+ MemberId from(nodeid, pid);
+ framing::Buffer buf(static_cast<char*>(msg), msg_len);
+ deliver(Event::decode(from, buf), l);
+}
+
+void Cluster::deliver(const Event& e, Lock&) {
+ if (state == LEFT) return;
+ QPID_LOG(trace, *this << " PUSH: " << e);
+ deliverQueue.push(e); // Otherwise enqueue for processing.
+}
+
+// Entry point: called when deliverQueue has events to process.
+void Cluster::delivered(PollableEventQueue::Queue& events) {
+ try {
+ for_each(events.begin(), events.end(), boost::bind(&Cluster::deliveredEvent, this, _1));
+ events.clear();
+ } catch (const std::exception& e) {
+ QPID_LOG(critical, *this << " error in cluster delivery: " << e.what());
+ leave();
+ }
+}
+
+void Cluster::deliveredEvent(const Event& e) {
+ Buffer buf(e);
+ AMQFrame frame;
+ if (e.isCluster()) {
+ while (frame.decode(buf)) {
+ QPID_LOG(trace, *this << " DLVR: " << e << " " << frame);
+ Mutex::ScopedLock l(lock); // FIXME aconway 2008-12-11: lock scope is too big.
+ ClusterDispatcher dispatch(*this, e.getMemberId(), l);
+ if (!framing::invoke(dispatch, *frame.getBody()).wasHandled())
+ throw Exception(QPID_MSG("Invalid cluster control"));
+ }
+ }
+ else { // e.isConnection()
+ if (state == NEWBIE) {
+ QPID_LOG(trace, *this << " DROP: " << e);
+ }
+ else {
+ boost::intrusive_ptr<Connection> connection = getConnection(e.getConnectionId());
+ if (!connection) return;
+ if (e.getType() == CONTROL) {
+ while (frame.decode(buf)) {
+ QPID_LOG(trace, *this << " DLVR: " << e << " " << frame);
+ connection->delivered(frame);
+ }
+ }
+ else {
+ QPID_LOG(trace, *this << " DLVR: " << e);
+ connection->deliverBuffer(buf);
+ }
+ }
+ }
+}
+
+struct AddrList {
+ const cpg_address* addrs;
+ int count;
+ const char *prefix, *suffix;
+ AddrList(const cpg_address* a, int n, const char* p="", const char* s="")
+ : addrs(a), count(n), prefix(p), suffix(s) {}
+};
+
+ostream& operator<<(ostream& o, const AddrList& a) {
+ if (!a.count) return o;
+ o << a.prefix;
+ for (const cpg_address* p = a.addrs; p < a.addrs+a.count; ++p) {
+ const char* reasonString;
+ switch (p->reason) {
+ case CPG_REASON_JOIN: reasonString = " (joined) "; break;
+ case CPG_REASON_LEAVE: reasonString = " (left) "; break;
+ case CPG_REASON_NODEDOWN: reasonString = " (node-down) "; break;
+ case CPG_REASON_NODEUP: reasonString = " (node-up) "; break;
+ case CPG_REASON_PROCDOWN: reasonString = " (process-down) "; break;
+ default: reasonString = " ";
+ }
+ qpid::cluster::MemberId member(*p);
+ o << member << reasonString;
+ }
+ return o << a.suffix;
+}
+
+// Entry point: called by IO to dispatch CPG events.
+void Cluster::dispatch(sys::DispatchHandle& h) {
+ try {
+ cpg.dispatchAll();
+ h.rewatch();
+ } catch (const std::exception& e) {
+ QPID_LOG(critical, *this << " error in cluster dispatch: " << e.what());
+ leave();
+ }
+}
+
+// Entry point: called if disconnected from CPG.
+void Cluster::disconnect(sys::DispatchHandle& ) {
+ QPID_LOG(critical, *this << " error disconnected from cluster");
+ try {
+ broker.shutdown();
+ } catch (const std::exception& e) {
+ QPID_LOG(error, *this << " error in shutdown: " << e.what());
+ }
+}
+
+void Cluster::configChange (
+ cpg_handle_t /*handle*/,
+ cpg_name */*group*/,
+ cpg_address *current, int nCurrent,
+ cpg_address *left, int nLeft,
+ cpg_address */*joined*/, int /*nJoined*/)
+{
+ Mutex::ScopedLock l(lock);
+ QPID_LOG(debug, *this << " config change: " << AddrList(current, nCurrent)
+ << AddrList(left, nLeft, "( ", ")"));
+ std::string addresses;
+ for (cpg_address* p = current; p < current+nCurrent; ++p)
+ addresses.append(MemberId(*p).str());
+ deliver(Event::control(ClusterConfigChangeBody(ProtocolVersion(), addresses), myId), l);
+}
+
+void Cluster::configChange(const MemberId&, const std::string& addresses, Lock& l) {
+ bool memberChange = map.configChange(addresses);
+ if (state == LEFT) return;
+
+ if (!map.isAlive(myId)) { // Final config change.
+ leave(l);
+ return;
+ }
+
+ if (state == INIT) { // First configChange
+ if (map.aliveCount() == 1) {
+ setClusterId(true);
+ // FIXME aconway 2008-12-11: Centralize transition to READY and associated actions eg mcast.release()
+ state = READY;
+ mcast.release();
+ QPID_LOG(notice, *this << " first in cluster");
+ if (mgmtObject!=0) mgmtObject->set_status("ACTIVE");
+ map = ClusterMap(myId, myUrl, true);
+ memberUpdate(l);
+ }
+ else { // Joining established group.
+ state = NEWBIE;
+ QPID_LOG(info, *this << " joining cluster: " << map);
+ mcast.mcastControl(ClusterDumpRequestBody(ProtocolVersion(), myUrl.str()), myId);
+ }
+ }
+ else if (state >= READY && memberChange)
+ memberUpdate(l);
+}
+
+
+
+
+void Cluster::tryMakeOffer(const MemberId& id, Lock& ) {
+ if (state == READY && map.isNewbie(id)) {
+ state = OFFER;
+ QPID_LOG(info, *this << " send dump-offer to " << id);
+ mcast.mcastControl(ClusterDumpOfferBody(ProtocolVersion(), id, clusterId), myId);
+ }
+}
+
+// Called from Broker::~Broker when broker is shut down. At this
+// point we know the poller has stopped so no poller callbacks will be
+// invoked. We must ensure that CPG has also shut down so no CPG
+// callbacks will be invoked.
+//
+void Cluster::brokerShutdown() {
+ QPID_LOG(notice, *this << " shutting down ");
+ if (state != LEFT) {
+ try { cpg.shutdown(); }
+ catch (const std::exception& e) {
+ QPID_LOG(error, *this << " during shutdown: " << e.what());
+ }
+ }
+ delete this;
+}
+
+void Cluster::dumpRequest(const MemberId& id, const std::string& url, Lock& l) {
+ map.dumpRequest(id, url);
+ tryMakeOffer(id, l);
+}
+
+void Cluster::ready(const MemberId& id, const std::string& url, Lock& l) {
+ if (map.ready(id, Url(url)))
+ memberUpdate(l);
+ if (state == CATCHUP && id == myId) {
+ state = READY;
+ mcast.release();
+ QPID_LOG(notice, *this << " caught up, active cluster member");
+ if (mgmtObject!=0) mgmtObject->set_status("ACTIVE");
+ mcast.release();
+ }
+}
+
+void Cluster::dumpOffer(const MemberId& dumper, uint64_t dumpeeInt, const Uuid& uuid, Lock& l) {
+ if (state == LEFT) return;
+ MemberId dumpee(dumpeeInt);
+ boost::optional<Url> url = map.dumpOffer(dumper, dumpee);
+ if (dumper == myId) {
+ assert(state == OFFER);
+ if (url) { // My offer was first.
+ dumpStart(dumpee, *url, l);
+ }
+ else { // Another offer was first.
+ state = READY;
+ mcast.release();
+ QPID_LOG(info, *this << " cancelled dump offer to " << dumpee);
+ tryMakeOffer(map.firstNewbie(), l); // Maybe make another offer.
+ }
+ }
+ else if (dumpee == myId && url) {
+ assert(state == NEWBIE);
+ setClusterId(uuid);
+ state = DUMPEE;
+ QPID_LOG(info, *this << " receiving dump from " << dumper);
+ deliverQueue.stop();
+ checkDumpIn(l);
+ }
+}
+
+// FIXME aconway 2008-10-15: no longer need a separate control now
+// that the dump control is in the deliver queue.
+void Cluster::dumpStart(const MemberId& dumpee, const Url& url, Lock&) {
+ if (state == LEFT) return;
+ assert(state == OFFER);
+ state = DUMPER;
+ QPID_LOG(info, *this << " stall for dump to " << dumpee << " at " << url);
+ deliverQueue.stop();
+ if (dumpThread.id()) dumpThread.join(); // Join the previous dumpthread.
+ dumpThread = Thread(
+ new DumpClient(myId, dumpee, url, broker, map, connections.values(),
+ boost::bind(&Cluster::dumpOutDone, this),
+ boost::bind(&Cluster::dumpOutError, this, _1)));
+}
+
+// Called in dump thread.
+void Cluster::dumpInDone(const ClusterMap& m) {
+ Lock l(lock);
+ dumpedMap = m;
+ checkDumpIn(l);
+}
+
+void Cluster::checkDumpIn(Lock& ) {
+ if (state == LEFT) return;
+ if (state == DUMPEE && dumpedMap) {
+ map = *dumpedMap;
+ mcast.mcastControl(ClusterReadyBody(ProtocolVersion(), myUrl.str()), myId);
+ state = CATCHUP;
+ QPID_LOG(info, *this << " received dump, starting catch-up");
+ deliverQueue.start();
+ }
+}
+
+void Cluster::dumpOutDone() {
+ Monitor::ScopedLock l(lock);
+ dumpOutDone(l);
+}
+
+void Cluster::dumpOutDone(Lock& l) {
+ assert(state == DUMPER);
+ state = READY;
+ mcast.release();
+ QPID_LOG(info, *this << " sent dump");
+ deliverQueue.start();
+ tryMakeOffer(map.firstNewbie(), l); // Try another offer
+}
+
+void Cluster::dumpOutError(const std::exception& e) {
+ Monitor::ScopedLock l(lock);
+ QPID_LOG(error, *this << " error sending dump: " << e.what());
+ dumpOutDone(l);
+}
+
+void Cluster ::shutdown(const MemberId& id, Lock& l) {
+ QPID_LOG(notice, *this << " received shutdown from " << id);
+ leave(l);
+}
+
+ManagementObject* Cluster::GetManagementObject() const { return mgmtObject; }
+
+Manageable::status_t Cluster::ManagementMethod (uint32_t methodId, Args&, string&) {
+ Lock l(lock);
+ QPID_LOG(debug, *this << " managementMethod [id=" << methodId << "]");
+ switch (methodId) {
+ case qmf::Cluster::METHOD_STOPCLUSTERNODE: stopClusterNode(l); break;
+ case qmf::Cluster::METHOD_STOPFULLCLUSTER: stopFullCluster(l); break;
+ default: return Manageable::STATUS_UNKNOWN_METHOD;
+ }
+ return Manageable::STATUS_OK;
+}
+
+void Cluster::stopClusterNode(Lock& l) {
+ QPID_LOG(notice, *this << " stopped by admin");
+ leave(l);
+}
+
+void Cluster::stopFullCluster(Lock& ) {
+ QPID_LOG(notice, *this << " shutting down cluster " << name);
+ mcast.mcastControl(ClusterShutdownBody(), myId);
+}
+
+void Cluster::memberUpdate(Lock& l) {
+ QPID_LOG(info, *this << " member update: " << map);
+ std::vector<Url> urls = getUrls(l);
+ size_t size = urls.size();
+ failoverExchange->setUrls(urls);
+
+ if (size == 1 && lastSize > 1 && state >= READY) {
+ QPID_LOG(info, *this << " last broker standing, update queue policies");
+ lastBroker = true;
+ broker.getQueues().updateQueueClusterState(true);
+ }
+ else if (size > 1 && lastBroker) {
+ QPID_LOG(info, *this << " last broker standing joined by " << size-1 << " replicas, updating queue policies" << size);
+ lastBroker = false;
+ broker.getQueues().updateQueueClusterState(false);
+ }
+ lastSize = size;
+
+ if (mgmtObject) {
+ mgmtObject->set_clusterSize(size);
+ string urlstr;
+ for(std::vector<Url>::iterator iter = urls.begin(); iter != urls.end(); iter++ ) {
+ if (iter != urls.begin()) urlstr += "\n";
+ urlstr += iter->str();
+ }
+ mgmtObject->set_members(urlstr);
+ }
+
+ // Close connections belonging to members that have now been excluded
+ connections.update(myId, map);
+}
+
+std::ostream& operator<<(std::ostream& o, const Cluster& cluster) {
+ static const char* STATE[] = { "INIT", "NEWBIE", "DUMPEE", "CATCHUP", "READY", "OFFER", "DUMPER", "LEFT" };
+ return o << cluster.myId << "(" << STATE[cluster.state] << ")";
+}
+
+MemberId Cluster::getId() const {
+ return myId; // Immutable, no need to lock.
+}
+
+broker::Broker& Cluster::getBroker() const {
+ return broker; // Immutable, no need to lock.
+}
+
+void Cluster::checkQuorum() {
+ if (!quorum.isQuorate()) {
+ QPID_LOG(critical, *this << " disconnected from cluster quorum, shutting down");
+ leave();
+ throw Exception(QPID_MSG(*this << " disconnected from cluster quorum."));
+ }
+}
+
+void Cluster::setClusterId(const Uuid& uuid) {
+ clusterId = uuid;
+ if (mgmtObject)
+ mgmtObject->set_clusterID(clusterId.str());
+ QPID_LOG(debug, *this << " cluster-id = " << clusterId);
+}
+
+}} // namespace qpid::cluster
diff --git a/RC9/qpid/cpp/src/qpid/cluster/Cluster.h b/RC9/qpid/cpp/src/qpid/cluster/Cluster.h
new file mode 100644
index 0000000000..b8fe61bf15
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/Cluster.h
@@ -0,0 +1,230 @@
+#ifndef QPID_CLUSTER_CLUSTER_H
+#define QPID_CLUSTER_CLUSTER_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "Cpg.h"
+#include "Event.h"
+#include "NoOpConnectionOutputHandler.h"
+#include "ClusterMap.h"
+#include "ConnectionMap.h"
+#include "FailoverExchange.h"
+#include "Quorum.h"
+#include "Multicaster.h"
+
+#include "qpid/broker/Broker.h"
+#include "qpid/sys/PollableQueue.h"
+#include "qpid/sys/Monitor.h"
+#include "qpid/sys/LockPtr.h"
+#include "qpid/management/Manageable.h"
+#include "qpid/Url.h"
+#include "qmf/org/apache/qpid/cluster/Cluster.h"
+
+#include <boost/intrusive_ptr.hpp>
+#include <boost/bind.hpp>
+#include <boost/optional.hpp>
+
+#include <algorithm>
+#include <vector>
+#include <map>
+
+namespace qpid {
+
+namespace framing {
+class AMQBody;
+class Uuid;
+}
+
+namespace cluster {
+
+class Connection;
+
+/**
+ * Connection to the cluster
+ *
+ * Threading notes: 3 thread categories: connection, deliver, dump.
+ *
+ */
+class Cluster : private Cpg::Handler, public management::Manageable {
+ public:
+ typedef boost::intrusive_ptr<Connection> ConnectionPtr;
+ typedef std::vector<ConnectionPtr> Connections;
+
+ /**
+ * Join a cluster.
+ */
+ Cluster(const std::string& name, const Url& url, broker::Broker&, bool useQuorum,
+ size_t readMax, size_t writeEstimate);
+
+ virtual ~Cluster();
+
+ // Connection map - called in connection threads.
+ void insert(const ConnectionPtr&);
+ void erase(ConnectionId);
+
+ // URLs of current cluster members - called in connection threads.
+ std::vector<Url> getUrls() const;
+ boost::shared_ptr<FailoverExchange> getFailoverExchange() const { return failoverExchange; }
+
+ // Leave the cluster - called in any thread.
+ void leave();
+
+ // Dump completed - called in dump thread
+ void dumpInDone(const ClusterMap&);
+
+ MemberId getId() const;
+ broker::Broker& getBroker() const;
+ Multicaster& getMulticast() { return mcast; }
+
+ boost::function<bool ()> isQuorate;
+ void checkQuorum(); // called in connection threads.
+
+ size_t getReadMax() { return readMax; }
+ size_t getWriteEstimate() { return writeEstimate; }
+
+ private:
+ typedef sys::LockPtr<Cluster,sys::Monitor> LockPtr;
+ typedef sys::LockPtr<const Cluster,sys::Monitor> ConstLockPtr;
+ typedef sys::Monitor::ScopedLock Lock;
+
+ typedef sys::PollableQueue<Event> PollableEventQueue;
+ typedef std::deque<Event> PlainEventQueue;
+
+ // NB: The final Lock& parameter on functions below is used to mark functions
+ // that should only be called by a function that already holds the lock.
+ // The parameter makes it hard to forget since you have to have an instance of
+ // a Lock to call the unlocked functions.
+
+ void leave(Lock&);
+ std::vector<Url> getUrls(Lock&) const;
+
+ // Make an offer if we can - called in deliver thread.
+ void tryMakeOffer(const MemberId&, Lock&);
+
+ // Called in main thread in ~Broker.
+ void brokerShutdown();
+
+ // Cluster controls implement XML methods from cluster.xml.
+ // Called in deliver thread.
+ //
+ void dumpRequest(const MemberId&, const std::string&, Lock&);
+ void dumpOffer(const MemberId& dumper, uint64_t dumpee, const framing::Uuid&, Lock&);
+ void ready(const MemberId&, const std::string&, Lock&);
+ void configChange(const MemberId&, const std::string& addresses, Lock& l);
+ void shutdown(const MemberId&, Lock&);
+ void delivered(PollableEventQueue::Queue&); // deliverQueue callback
+ void deliveredEvent(const Event&);
+
+ // Helper, called in deliver thread.
+ void dumpStart(const MemberId& dumpee, const Url& url, Lock&);
+
+ // CPG callbacks, called in CPG IO thread.
+ void dispatch(sys::DispatchHandle&); // Dispatch CPG events.
+ void disconnect(sys::DispatchHandle&); // PG was disconnected
+
+ void deliver( // CPG deliver callback.
+ cpg_handle_t /*handle*/,
+ struct cpg_name *group,
+ uint32_t /*nodeid*/,
+ uint32_t /*pid*/,
+ void* /*msg*/,
+ int /*msg_len*/);
+
+ void deliver(const Event& e, Lock&);
+
+ void configChange( // CPG config change callback.
+ cpg_handle_t /*handle*/,
+ struct cpg_name */*group*/,
+ struct cpg_address */*members*/, int /*nMembers*/,
+ struct cpg_address */*left*/, int /*nLeft*/,
+ struct cpg_address */*joined*/, int /*nJoined*/
+ );
+
+ boost::intrusive_ptr<cluster::Connection> getConnection(const ConnectionId&);
+
+ virtual qpid::management::ManagementObject* GetManagementObject() const;
+ virtual management::Manageable::status_t ManagementMethod (uint32_t methodId, management::Args& args, std::string& text);
+
+ void stopClusterNode(Lock&);
+ void stopFullCluster(Lock&);
+ void memberUpdate(Lock&);
+
+ // Called in connection IO threads .
+ void checkDumpIn(Lock&);
+
+ // Called in DumpClient thread.
+ void dumpOutDone();
+ void dumpOutError(const std::exception&);
+ void dumpOutDone(Lock&);
+
+ void setClusterId(const framing::Uuid&);
+
+ // Immutable members set on construction, never changed.
+ broker::Broker& broker;
+ boost::shared_ptr<sys::Poller> poller;
+ Cpg cpg;
+ const std::string name;
+ const Url myUrl;
+ const MemberId myId;
+ const size_t readMax;
+ const size_t writeEstimate;
+ framing::Uuid clusterId;
+ NoOpConnectionOutputHandler shadowOut;
+ sys::DispatchHandle cpgDispatchHandle;
+
+
+ // Thread safe members
+ Multicaster mcast;
+ qmf::org::apache::qpid::cluster::Cluster* mgmtObject; // mgnt owns lifecycle
+ PollableEventQueue deliverQueue;
+ ConnectionMap connections;
+ boost::shared_ptr<FailoverExchange> failoverExchange;
+ Quorum quorum;
+
+ // Remaining members are protected by lock.
+ mutable sys::Monitor lock;
+
+ // Local cluster state, cluster map
+ enum {
+ INIT, ///< Initial state, no CPG messages received.
+ NEWBIE, ///< Sent dump request, waiting for dump offer.
+ DUMPEE, ///< Stalled receive queue at dump offer, waiting for dump to complete.
+ CATCHUP, ///< Dump complete, unstalled but has not yet seen own "ready" event.
+ READY, ///< Fully operational
+ OFFER, ///< Sent an offer, waiting for accept/reject.
+ DUMPER, ///< Offer accepted, sending a state dump.
+ LEFT ///< Final state, left the cluster.
+ } state;
+ ClusterMap map;
+ size_t lastSize;
+ bool lastBroker;
+
+ // Dump related
+ sys::Thread dumpThread;
+ boost::optional<ClusterMap> dumpedMap;
+
+ friend std::ostream& operator<<(std::ostream&, const Cluster&);
+ friend class ClusterDispatcher;
+};
+
+}} // namespace qpid::cluster
+
+
+
+#endif /*!QPID_CLUSTER_CLUSTER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/cluster/ClusterLeaveException.h b/RC9/qpid/cpp/src/qpid/cluster/ClusterLeaveException.h
new file mode 100644
index 0000000000..e5bdbc560a
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/ClusterLeaveException.h
@@ -0,0 +1,35 @@
+#ifndef QPID_CLUSTER_CLUSTERLEAVEEXCEPTION_H
+#define QPID_CLUSTER_CLUSTERLEAVEEXCEPTION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/Exception.h"
+
+namespace qpid {
+namespace cluster {
+
+struct ClusterLeaveException : public Exception
+{
+ ClusterLeaveException(const std::string& message=std::string()) : Exception(message) {}
+};
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_CLUSTERLEAVEEXCEPTION_H*/
diff --git a/RC9/qpid/cpp/src/qpid/cluster/ClusterMap.cpp b/RC9/qpid/cpp/src/qpid/cluster/ClusterMap.cpp
new file mode 100644
index 0000000000..873f0be928
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/ClusterMap.cpp
@@ -0,0 +1,173 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "ClusterMap.h"
+#include "qpid/Url.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/log/Statement.h"
+#include <boost/bind.hpp>
+#include <algorithm>
+#include <functional>
+#include <iterator>
+#include <ostream>
+
+namespace qpid {
+using namespace framing;
+
+namespace cluster {
+
+namespace {
+
+void addFieldTableValue(FieldTable::ValueMap::value_type vt, ClusterMap::Map& map, ClusterMap::Set& set) {
+ MemberId id(vt.first);
+ set.insert(id);
+ std::string url = vt.second->get<std::string>();
+ if (!url.empty())
+ map.insert(ClusterMap::Map::value_type(id, Url(url)));
+}
+
+void insertFieldTableFromMapValue(FieldTable& ft, const ClusterMap::Map::value_type& vt) {
+ ft.setString(vt.first.str(), vt.second.str());
+}
+
+void assignFieldTable(FieldTable& ft, const ClusterMap::Map& map) {
+ ft.clear();
+ std::for_each(map.begin(), map.end(), boost::bind(&insertFieldTableFromMapValue, boost::ref(ft), _1));
+}
+
+}
+
+ClusterMap::ClusterMap() {}
+
+ClusterMap::ClusterMap(const MemberId& id, const Url& url , bool isMember) {
+ alive.insert(id);
+ if (isMember)
+ members[id] = url;
+ else
+ newbies[id] = url;
+}
+
+ClusterMap::ClusterMap(const FieldTable& newbiesFt, const FieldTable& membersFt) {
+ std::for_each(newbiesFt.begin(), newbiesFt.end(), boost::bind(&addFieldTableValue, _1, boost::ref(newbies), boost::ref(alive)));
+ std::for_each(membersFt.begin(), membersFt.end(), boost::bind(&addFieldTableValue, _1, boost::ref(members), boost::ref(alive)));
+}
+
+ClusterConnectionMembershipBody ClusterMap::asMethodBody() const {
+ framing::ClusterConnectionMembershipBody b;
+ b.getNewbies().clear();
+ std::for_each(newbies.begin(), newbies.end(), boost::bind(&insertFieldTableFromMapValue, boost::ref(b.getNewbies()), _1));
+ for(Set::const_iterator i = alive.begin(); i != alive.end(); ++i) {
+ if (!isMember(*i) && !isNewbie(*i))
+ b.getNewbies().setString(i->str(), std::string());
+ }
+ b.getMembers().clear();
+ std::for_each(members.begin(), members.end(), boost::bind(&insertFieldTableFromMapValue, boost::ref(b.getMembers()), _1));
+ return b;
+}
+
+bool ClusterMap::configChange(
+ cpg_address *current, int nCurrent,
+ cpg_address *left, int nLeft,
+ cpg_address */*joined*/, int /*nJoined*/)
+{
+ cpg_address* a;
+ bool memberChange=false;
+ for (a = left; a != left+nLeft; ++a) {
+ memberChange = memberChange || members.erase(*a);
+ newbies.erase(*a);
+ }
+ alive.clear();
+ std::copy(current, current+nCurrent, std::inserter(alive, alive.end()));
+ return memberChange;
+}
+
+Url ClusterMap::getUrl(const Map& map, const MemberId& id) {
+ Map::const_iterator i = map.find(id);
+ return i == map.end() ? Url() : i->second;
+}
+
+MemberId ClusterMap::firstNewbie() const {
+ return newbies.empty() ? MemberId() : newbies.begin()->first;
+}
+
+std::vector<Url> ClusterMap::memberUrls() const {
+ std::vector<Url> urls(members.size());
+ std::transform(members.begin(), members.end(), urls.begin(),
+ boost::bind(&Map::value_type::second, _1));
+ return urls;
+}
+
+std::ostream& operator<<(std::ostream& o, const ClusterMap::Map& m) {
+ std::ostream_iterator<MemberId> oi(o);
+ std::transform(m.begin(), m.end(), oi, boost::bind(&ClusterMap::Map::value_type::first, _1));
+ return o;
+}
+
+std::ostream& operator<<(std::ostream& o, const ClusterMap& m) {
+ for (ClusterMap::Set::const_iterator i = m.alive.begin(); i != m.alive.end(); ++i) {
+ o << *i;
+ if (m.isMember(*i)) o << "(member)";
+ else if (m.isNewbie(*i)) o << "(newbie)";
+ else o << "(unknown)";
+ o << " ";
+ }
+ return o;
+}
+
+bool ClusterMap::dumpRequest(const MemberId& id, const std::string& url) {
+ if (isAlive(id)) {
+ newbies[id] = Url(url);
+ return true;
+ }
+ return false;
+}
+
+bool ClusterMap::ready(const MemberId& id, const Url& url) {
+ return isAlive(id) && members.insert(Map::value_type(id,url)).second;
+}
+
+bool ClusterMap::configChange(const std::string& addresses) {
+ bool memberChange = false;
+ Set update;
+ for (std::string::const_iterator i = addresses.begin(); i < addresses.end(); i += 8)
+ update.insert(MemberId(std::string(i, i+8)));
+ Set removed;
+ std::set_difference(alive.begin(), alive.end(),
+ update.begin(), update.end(),
+ std::inserter(removed, removed.begin()));
+ alive = update;
+ for (Set::const_iterator i = removed.begin(); i != removed.end(); ++i) {
+ memberChange = memberChange || members.erase(*i);
+ newbies.erase(*i);
+ }
+ return memberChange;
+}
+
+boost::optional<Url> ClusterMap::dumpOffer(const MemberId& from, const MemberId& to) {
+ Map::iterator i = newbies.find(to);
+ if (isAlive(from) && i != newbies.end()) {
+ Url url= i->second;
+ newbies.erase(i); // No longer a potential dumpee.
+ return url;
+ }
+ return boost::optional<Url>();
+}
+
+}} // namespace qpid::cluster
diff --git a/RC9/qpid/cpp/src/qpid/cluster/ClusterMap.h b/RC9/qpid/cpp/src/qpid/cluster/ClusterMap.h
new file mode 100644
index 0000000000..5c1981269f
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/ClusterMap.h
@@ -0,0 +1,99 @@
+#ifndef QPID_CLUSTER_CLUSTERMAP_H
+#define QPID_CLUSTER_CLUSTERMAP_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "types.h"
+#include "qpid/Url.h"
+#include "qpid/framing/ClusterConnectionMembershipBody.h"
+
+#include <boost/function.hpp>
+#include <boost/optional.hpp>
+
+#include <vector>
+#include <deque>
+#include <map>
+#include <set>
+#include <iosfwd>
+
+namespace qpid {
+namespace cluster {
+
+/**
+ * Map of established cluster members and newbies waiting for a brain dump.
+ */
+class ClusterMap {
+ public:
+ typedef std::map<MemberId, Url> Map;
+ typedef std::set<MemberId> Set;
+
+ ClusterMap();
+ ClusterMap(const MemberId& id, const Url& url, bool isReady);
+ ClusterMap(const framing::FieldTable& urls, const framing::FieldTable& states);
+
+ /** Update from config change.
+ *@return true if member set changed.
+ */
+ bool configChange(
+ cpg_address *current, int nCurrent,
+ cpg_address *left, int nLeft,
+ cpg_address *joined, int nJoined);
+
+ bool configChange(const std::string& addresses);
+
+ bool isNewbie(const MemberId& id) const { return newbies.find(id) != newbies.end(); }
+ bool isMember(const MemberId& id) const { return members.find(id) != members.end(); }
+ bool isAlive(const MemberId& id) const { return alive.find(id) != alive.end(); }
+
+ Url getNewbieUrl(const MemberId& id) { return getUrl(newbies, id); }
+ Url getMemberUrl(const MemberId& id) { return getUrl(members, id); }
+
+ /** First newbie in the cluster in ID order, target for offers */
+ MemberId firstNewbie() const;
+
+ /** Convert map contents to a cluster control body. */
+ framing::ClusterConnectionMembershipBody asMethodBody() const;
+
+ size_t aliveCount() const { return alive.size(); }
+ size_t memberCount() const { return members.size(); }
+ std::vector<Url> memberUrls() const;
+
+ bool dumpRequest(const MemberId& id, const std::string& url);
+ /** Return non-empty Url if accepted */
+ boost::optional<Url> dumpOffer(const MemberId& from, const MemberId& to);
+
+ /**@return true If this is a new member */
+ bool ready(const MemberId& id, const Url&);
+
+ private:
+ Url getUrl(const Map& map, const MemberId& id);
+
+ Map newbies, members;
+ Set alive;
+
+ friend std::ostream& operator<<(std::ostream&, const Map&);
+ friend std::ostream& operator<<(std::ostream&, const ClusterMap&);
+};
+
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_CLUSTERMAP_H*/
diff --git a/RC9/qpid/cpp/src/qpid/cluster/ClusterPlugin.cpp b/RC9/qpid/cpp/src/qpid/cluster/ClusterPlugin.cpp
new file mode 100644
index 0000000000..0f4944d392
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/ClusterPlugin.cpp
@@ -0,0 +1,106 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "Connection.h"
+#include "ConnectionCodec.h"
+
+#include "qpid/cluster/Cluster.h"
+#include "qpid/cluster/ConnectionCodec.h"
+
+#include "qpid/broker/Broker.h"
+#include "qpid/Plugin.h"
+#include "qpid/Options.h"
+#include "qpid/shared_ptr.h"
+#include "qpid/log/Statement.h"
+
+#include <boost/utility/in_place_factory.hpp>
+#include <boost/scoped_ptr.hpp>
+
+namespace qpid {
+namespace cluster {
+
+using namespace std;
+using broker::Broker;
+
+struct ClusterValues {
+ string name;
+ string url;
+ bool quorum;
+ size_t readMax, writeEstimate;
+
+ // FIXME aconway 2008-12-09: revisit default.
+ ClusterValues() : quorum(false), readMax(0), writeEstimate(64) {}
+
+ Url getUrl(uint16_t port) const {
+ if (url.empty()) return Url::getIpAddressesUrl(port);
+ return Url(url);
+ }
+};
+
+/** Note separating options from values to work around boost version differences.
+ * Old boost takes a reference to options objects, but new boost makes a copy.
+ * New boost allows a shared_ptr but that's not compatible with old boost.
+ */
+struct ClusterOptions : public Options {
+ ClusterValues& values;
+
+ ClusterOptions(ClusterValues& v) : Options("Cluster Options"), values(v) {
+ addOptions()
+ ("cluster-name", optValue(values.name, "NAME"), "Name of cluster to join")
+ ("cluster-url", optValue(values.url,"URL"),
+ "URL of this broker, advertized to the cluster.\n"
+ "Defaults to a URL listing all the local IP addresses\n")
+#if HAVE_LIBCMAN
+ ("cluster-cman", optValue(values.quorum), "Integrate with Cluster Manager (CMAN) cluster.")
+#endif
+ ("cluster-read-max", optValue(values.readMax,"N"),
+ "Throttle read rate from client connections.")
+ ("cluster-write-estimate", optValue(values.writeEstimate, "Kb"),
+ "Estimate connection write rate per multicast cycle")
+ ;
+ }
+};
+
+struct ClusterPlugin : public Plugin {
+
+ ClusterValues values;
+ ClusterOptions options;
+ Cluster* cluster;
+ boost::scoped_ptr<ConnectionCodec::Factory> factory;
+
+ ClusterPlugin() : options(values), cluster(0) {}
+
+ Options* getOptions() { return &options; }
+
+ void initialize(Plugin::Target& target) {
+ if (values.name.empty()) return; // Only if --cluster-name option was specified.
+ Broker* broker = dynamic_cast<Broker*>(&target);
+ if (!broker) return;
+ cluster = new Cluster(values.name, values.getUrl(broker->getPort(Broker::TCP_TRANSPORT)), *broker, values.quorum, values.readMax, values.writeEstimate*1024);
+ broker->setConnectionFactory(
+ boost::shared_ptr<sys::ConnectionCodec::Factory>(
+ new ConnectionCodec::Factory(broker->getConnectionFactory(), *cluster)));
+ broker->getExchanges().registerExchange(cluster->getFailoverExchange());
+ }
+
+ void earlyInitialize(Plugin::Target&) {}
+};
+
+static ClusterPlugin instance; // Static initialization.
+
+}} // namespace qpid::cluster
diff --git a/RC9/qpid/cpp/src/qpid/cluster/Connection.cpp b/RC9/qpid/cpp/src/qpid/cluster/Connection.cpp
new file mode 100644
index 0000000000..f0d38bf299
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/Connection.cpp
@@ -0,0 +1,370 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "Connection.h"
+#include "DumpClient.h"
+#include "Cluster.h"
+
+#include "qpid/broker/SessionState.h"
+#include "qpid/broker/SemanticState.h"
+#include "qpid/broker/TxBuffer.h"
+#include "qpid/broker/TxPublish.h"
+#include "qpid/broker/TxAccept.h"
+#include "qpid/broker/RecoveredEnqueue.h"
+#include "qpid/broker/RecoveredDequeue.h"
+#include "qpid/broker/Exchange.h"
+#include "qpid/broker/Queue.h"
+#include "qpid/framing/enum.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/AllInvoker.h"
+#include "qpid/framing/DeliveryProperties.h"
+#include "qpid/framing/ClusterConnectionDeliverCloseBody.h"
+#include "qpid/framing/ConnectionCloseBody.h"
+#include "qpid/framing/ConnectionCloseOkBody.h"
+#include "qpid/log/Statement.h"
+
+#include <boost/current_function.hpp>
+
+// TODO aconway 2008-11-03:
+//
+// Disproportionate amount of code here is dedicated to receiving a
+// brain-dump when joining a cluster and building initial
+// state. Should be separated out into its own classes.
+//
+
+
+namespace qpid {
+namespace cluster {
+
+using namespace framing;
+
+NoOpConnectionOutputHandler Connection::discardHandler;
+
+// Shadow connections
+Connection::Connection(Cluster& c, sys::ConnectionOutputHandler& out,
+ const std::string& wrappedId, ConnectionId myId)
+ : cluster(c), self(myId), catchUp(false), output(*this, out),
+ connection(&output, cluster.getBroker(), wrappedId)
+{ init(); }
+
+// Local connections
+Connection::Connection(Cluster& c, sys::ConnectionOutputHandler& out,
+ const std::string& wrappedId, MemberId myId, bool isCatchUp)
+ : cluster(c), self(myId, this), catchUp(isCatchUp), output(*this, out),
+ connection(&output, cluster.getBroker(), wrappedId)
+{ init(); }
+
+void Connection::init() {
+ QPID_LOG(debug, cluster << " new connection: " << *this);
+ if (isLocal() && !isCatchUp()) {
+ output.giveReadCredit(cluster.getReadMax());
+ }
+}
+
+Connection::~Connection() {
+ QPID_LOG(debug, cluster << " deleted connection: " << *this);
+}
+
+bool Connection::doOutput() {
+ return output.doOutput();
+}
+
+// Delivery of doOutput allows us to run the real connection doOutput()
+// which stocks up the write buffers with data.
+//
+void Connection::deliverDoOutput(uint32_t requested) {
+ assert(!catchUp);
+ output.deliverDoOutput(requested);
+}
+
+// Received from a directly connected client.
+void Connection::received(framing::AMQFrame& f) {
+ QPID_LOG(trace, cluster << " RECV " << *this << ": " << f);
+ if (isLocal()) {
+ currentChannel = f.getChannel();
+ if (!framing::invoke(*this, *f.getBody()).wasHandled())
+ connection.received(f);
+ }
+ else { // Shadow or dumped ex catch-up connection.
+ if (f.getMethod() && f.getMethod()->isA<ConnectionCloseBody>()) {
+ if (isShadow()) {
+ QPID_LOG(debug, cluster << " inserting connection " << *this);
+ cluster.insert(boost::intrusive_ptr<Connection>(this));
+ }
+ AMQFrame ok(in_place<ConnectionCloseOkBody>());
+ connection.getOutput().send(ok);
+ output.setOutputHandler(discardHandler);
+ catchUp = false;
+ }
+ else
+ QPID_LOG(warning, cluster << " ignoring unexpected frame " << *this << ": " << f);
+ }
+}
+
+bool Connection::checkUnsupported(const AMQBody& body) {
+ std::string message;
+ if (body.getMethod()) {
+ switch (body.getMethod()->amqpClassId()) {
+ case DTX_CLASS_ID: message = "DTX transactions are not currently supported by cluster."; break;
+ }
+ }
+ else if (body.type() == HEADER_BODY) {
+ const DeliveryProperties* dp = static_cast<const AMQHeaderBody&>(body).get<DeliveryProperties>();
+ if (dp && dp->getTtl()) message = "Message TTL is not currently supported by cluster.";
+ }
+ if (!message.empty())
+ connection.close(connection::CLOSE_CODE_FRAMING_ERROR, message);
+ return !message.empty();
+}
+
+// Delivered from cluster.
+void Connection::delivered(framing::AMQFrame& f) {
+ QPID_LOG(trace, cluster << " RECV: " << *this << ": " << f);
+ assert(!catchUp);
+ currentChannel = f.getChannel();
+ if (!framing::invoke(*this, *f.getBody()).wasHandled() // Connection contol.
+ && !checkUnsupported(*f.getBody())) // Unsupported operation.
+ {
+ connection.received(f); // Pass to broker connection.
+ }
+}
+
+// A local connection is closed by the network layer.
+void Connection::closed() {
+ try {
+ if (catchUp) {
+ QPID_LOG(critical, cluster << " catch-up connection closed prematurely " << *this);
+ cluster.leave();
+ }
+ else if (isDumped()) {
+ QPID_LOG(debug, cluster << " closed dump connection " << *this);
+ connection.closed();
+ }
+ else if (isLocal()) {
+ QPID_LOG(debug, cluster << " local close of replicated connection " << *this);
+ // This was a local replicated connection. Multicast a deliver
+ // closed and process any outstanding frames from the cluster
+ // until self-delivery of deliver-close.
+ output.setOutputHandler(discardHandler);
+ cluster.getMulticast().mcastControl(ClusterConnectionDeliverCloseBody(), self);
+ }
+ }
+ catch (const std::exception& e) {
+ QPID_LOG(error, cluster << " error closing connection " << *this << ": " << e.what());
+ }
+}
+
+// Self-delivery of close message, close the connection.
+void Connection::deliverClose () {
+ assert(!catchUp);
+ connection.closed();
+ cluster.erase(self);
+}
+
+// Member of a shadow connection left the cluster.
+void Connection::left() {
+ assert(isShadow());
+ connection.closed();
+}
+
+// Decode data from local clients.
+size_t Connection::decode(const char* buffer, size_t size) {
+ if (catchUp) { // Handle catch-up locally.
+ Buffer buf(const_cast<char*>(buffer), size);
+ while (localDecoder.decode(buf))
+ received(localDecoder.frame);
+ }
+ else { // Multicast local connections.
+ assert(isLocal());
+ cluster.getMulticast().mcastBuffer(buffer, size, self);
+ }
+ return size;
+}
+
+void Connection::deliverBuffer(Buffer& buf) {
+ assert(!catchUp);
+ ++deliverSeq;
+ while (mcastDecoder.decode(buf))
+ delivered(mcastDecoder.frame);
+ if (cluster.getReadMax())
+ output.giveReadCredit(1);
+}
+
+broker::SessionState& Connection::sessionState() {
+ return *connection.getChannel(currentChannel).getSession();
+}
+
+broker::SemanticState& Connection::semanticState() {
+ return sessionState().getSemanticState();
+}
+
+void Connection::consumerState(const string& name, bool blocked, bool notifyEnabled) {
+ broker::SemanticState::ConsumerImpl& c = semanticState().find(name);
+ c.setBlocked(blocked);
+ if (notifyEnabled) c.enableNotify(); else c.disableNotify();
+}
+
+void Connection::sessionState(
+ const SequenceNumber& replayStart,
+ const SequenceNumber& sendCommandPoint,
+ const SequenceSet& sentIncomplete,
+ const SequenceNumber& expected,
+ const SequenceNumber& received,
+ const SequenceSet& unknownCompleted,
+ const SequenceSet& receivedIncomplete)
+{
+ sessionState().setState(
+ replayStart,
+ sendCommandPoint,
+ sentIncomplete,
+ expected,
+ received,
+ unknownCompleted,
+ receivedIncomplete);
+ QPID_LOG(debug, cluster << " received session state dump for " << sessionState().getId());
+}
+
+void Connection::shadowReady(uint64_t memberId, uint64_t connectionId) {
+ ConnectionId shadow = ConnectionId(memberId, connectionId);
+ QPID_LOG(debug, cluster << " catch-up connection " << *this << " becomes shadow " << shadow);
+ self = shadow;
+}
+
+void Connection::membership(const FieldTable& newbies, const FieldTable& members) {
+ QPID_LOG(debug, cluster << " incoming dump complete on connection " << *this);
+ cluster.dumpInDone(ClusterMap(newbies, members));
+ self.second = 0; // Mark this as completed dump connection.
+}
+
+bool Connection::isLocal() const {
+ return self.first == cluster.getId() && self.second == this;
+}
+
+bool Connection::isShadow() const {
+ return self.first != cluster.getId();
+}
+
+bool Connection::isDumped() const {
+ return self.first == cluster.getId() && self.second == 0;
+}
+
+
+shared_ptr<broker::Queue> Connection::findQueue(const std::string& qname) {
+ shared_ptr<broker::Queue> queue = cluster.getBroker().getQueues().find(qname);
+ if (!queue) throw Exception(QPID_MSG(cluster << " can't find queue " << qname));
+ return queue;
+}
+
+broker::QueuedMessage Connection::getDumpMessage() {
+ broker::QueuedMessage m = findQueue(DumpClient::DUMP)->get();
+ if (!m.payload) throw Exception(QPID_MSG(cluster << " empty dump queue"));
+ return m;
+}
+
+void Connection::deliveryRecord(const string& qname,
+ const SequenceNumber& position,
+ const string& tag,
+ const SequenceNumber& id,
+ bool acquired,
+ bool accepted,
+ bool cancelled,
+ bool completed,
+ bool ended,
+ bool windowing,
+ uint32_t credit)
+{
+ broker::QueuedMessage m;
+ broker::Queue::shared_ptr queue = findQueue(qname);
+ if (!ended) { // Has a message
+ if (acquired) // Message is on the dump queue
+ m = getDumpMessage();
+ else // Message at original position in original queue
+ m = queue->find(position);
+ if (!m.payload)
+ throw Exception(QPID_MSG("deliveryRecord no dump message"));
+ }
+
+ broker::DeliveryRecord dr(m, queue, tag, acquired, accepted, windowing, credit);
+ dr.setId(id);
+ if (cancelled) dr.cancel(dr.getTag());
+ if (completed) dr.complete();
+ if (ended) dr.setEnded(); // Exsitance of message
+ semanticState().record(dr); // Part of the session's unacked list.
+}
+
+void Connection::queuePosition(const string& qname, const SequenceNumber& position) {
+ shared_ptr<broker::Queue> q = cluster.getBroker().getQueues().find(qname);
+ if (!q) throw InvalidArgumentException(QPID_MSG("Invalid queue name " << qname));
+ q->setPosition(position);
+}
+
+std::ostream& operator<<(std::ostream& o, const Connection& c) {
+ const char* type="unknown";
+ if (c.isLocal()) type = "local";
+ else if (c.isShadow()) type = "shadow";
+ else if (c.isDumped()) type = "dumped";
+ return o << c.getId() << "(" << type << (c.isCatchUp() ? ",catchup" : "") << ")";
+}
+
+void Connection::txStart() {
+ txBuffer = make_shared_ptr(new broker::TxBuffer());
+}
+void Connection::txAccept(const framing::SequenceSet& acked) {
+ txBuffer->enlist(make_shared_ptr(new broker::TxAccept(acked, semanticState().getUnacked())));
+}
+
+void Connection::txDequeue(const std::string& queue) {
+ txBuffer->enlist(make_shared_ptr(new broker::RecoveredDequeue(findQueue(queue), getDumpMessage().payload)));
+}
+
+void Connection::txEnqueue(const std::string& queue) {
+ txBuffer->enlist(make_shared_ptr(new broker::RecoveredEnqueue(findQueue(queue), getDumpMessage().payload)));
+}
+
+void Connection::txPublish(const framing::Array& queues, bool delivered) {
+ boost::shared_ptr<broker::TxPublish> txPub(new broker::TxPublish(getDumpMessage().payload));
+ for (framing::Array::const_iterator i = queues.begin(); i != queues.end(); ++i)
+ txPub->deliverTo(findQueue((*i)->get<std::string>()));
+ txPub->delivered = delivered;
+ txBuffer->enlist(txPub);
+}
+
+void Connection::txEnd() {
+ semanticState().setTxBuffer(txBuffer);
+}
+
+void Connection::accumulatedAck(const qpid::framing::SequenceSet& s) {
+ semanticState().setAccumulatedAck(s);
+}
+
+void Connection::exchange(const std::string& encoded) {
+ Buffer buf(const_cast<char*>(encoded.data()), encoded.size());
+ broker::Exchange::shared_ptr ex = broker::Exchange::decode(cluster.getBroker().getExchanges(), buf);
+ QPID_LOG(debug, cluster << " decoded exchange " << ex->getName());
+}
+
+void Connection::queue(const std::string& encoded) {
+ Buffer buf(const_cast<char*>(encoded.data()), encoded.size());
+ broker::Queue::shared_ptr q = broker::Queue::decode(cluster.getBroker().getQueues(), buf);
+ QPID_LOG(debug, cluster << " decoded queue " << q->getName());
+}
+
+}} // namespace qpid::cluster
+
diff --git a/RC9/qpid/cpp/src/qpid/cluster/Connection.h b/RC9/qpid/cpp/src/qpid/cluster/Connection.h
new file mode 100644
index 0000000000..29e42ce534
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/Connection.h
@@ -0,0 +1,177 @@
+#ifndef QPID_CLUSTER_CONNECTION_H
+#define QPID_CLUSTER_CONNECTION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "types.h"
+#include "WriteEstimate.h"
+#include "OutputInterceptor.h"
+#include "NoOpConnectionOutputHandler.h"
+
+#include "qpid/broker/Connection.h"
+#include "qpid/amqp_0_10/Connection.h"
+#include "qpid/sys/ConnectionInputHandler.h"
+#include "qpid/sys/ConnectionOutputHandler.h"
+#include "qpid/framing/FrameDecoder.h"
+#include "qpid/framing/SequenceNumber.h"
+
+#include <iosfwd>
+
+namespace qpid {
+
+namespace framing { class AMQFrame; }
+
+namespace broker {
+class SemanticState;
+class QueuedMessage;
+class TxBuffer;
+class TxAccept;
+}
+
+namespace cluster {
+class Cluster;
+
+/** Intercept broker::Connection calls for shadow and local cluster connections. */
+class Connection :
+ public RefCounted,
+ public sys::ConnectionInputHandler,
+ public framing::AMQP_AllOperations::ClusterConnectionHandler
+
+{
+ public:
+ /** Local connection, use this in ConnectionId */
+ Connection(Cluster&, sys::ConnectionOutputHandler& out, const std::string& id, MemberId, bool catchUp);
+ /** Shadow connection */
+ Connection(Cluster&, sys::ConnectionOutputHandler& out, const std::string& id, ConnectionId);
+ ~Connection();
+
+ ConnectionId getId() const { return self; }
+ broker::Connection& getBrokerConnection() { return connection; }
+
+ /** True for connections from direct clients of local broker */
+ bool isLocal() const;
+
+ /** True for connections that are shadowing remote broker connections */
+ bool isShadow() const;
+
+ /** True if the connection is in "catch-up" mode: building initial broker state. */
+ bool isCatchUp() const { return catchUp; }
+
+ /** True if the connection is a completed shared dump connection */
+ bool isDumped() const;
+
+ Cluster& getCluster() { return cluster; }
+
+ // ConnectionInputHandler methods
+ void received(framing::AMQFrame&);
+ void closed();
+ bool doOutput();
+ bool hasOutput() { return connection.hasOutput(); }
+ void idleOut() { connection.idleOut(); }
+ void idleIn() { connection.idleIn(); }
+
+ /** Called if the connectors member has left the cluster */
+ void left();
+
+ // ConnectionCodec methods
+ size_t decode(const char* buffer, size_t size);
+
+ // Called for data delivered from the cluster.
+ void deliverBuffer(framing::Buffer&);
+ void delivered(framing::AMQFrame&);
+
+ void consumerState(const std::string& name, bool blocked, bool notifyEnabled);
+
+ // ==== Used in catch-up mode to build initial state.
+ //
+ // State dump methods.
+ void sessionState(const framing::SequenceNumber& replayStart,
+ const framing::SequenceNumber& sendCommandPoint,
+ const framing::SequenceSet& sentIncomplete,
+ const framing::SequenceNumber& expected,
+ const framing::SequenceNumber& received,
+ const framing::SequenceSet& unknownCompleted, const SequenceSet& receivedIncomplete);
+
+ void shadowReady(uint64_t memberId, uint64_t connectionId);
+
+ void membership(const framing::FieldTable&, const framing::FieldTable&);
+
+ void deliveryRecord(const std::string& queue,
+ const framing::SequenceNumber& position,
+ const std::string& tag,
+ const framing::SequenceNumber& id,
+ bool acquired,
+ bool accepted,
+ bool cancelled,
+ bool completed,
+ bool ended,
+ bool windowing,
+ uint32_t credit);
+
+ void queuePosition(const std::string&, const framing::SequenceNumber&);
+
+ void txStart();
+ void txAccept(const framing::SequenceSet&);
+ void txDequeue(const std::string&);
+ void txEnqueue(const std::string&);
+ void txPublish(const qpid::framing::Array&, bool);
+ void txEnd();
+ void accumulatedAck(const qpid::framing::SequenceSet&);
+
+ // Encoded queue/exchange replication.
+ void queue(const std::string& encoded);
+ void exchange(const std::string& encoded);
+
+ private:
+ void init();
+ bool checkUnsupported(const framing::AMQBody& body);
+ void deliverClose();
+ void deliverDoOutput(uint32_t requested);
+ void sendDoOutput();
+
+ boost::shared_ptr<broker::Queue> findQueue(const std::string& qname);
+ broker::SessionState& sessionState();
+ broker::SemanticState& semanticState();
+ broker::QueuedMessage getDumpMessage();
+
+ static NoOpConnectionOutputHandler discardHandler;
+
+ Cluster& cluster;
+ ConnectionId self;
+ bool catchUp;
+ WriteEstimate writeEstimate;
+ OutputInterceptor output;
+ framing::FrameDecoder localDecoder;
+ framing::FrameDecoder mcastDecoder;
+ broker::Connection connection;
+ framing::SequenceNumber deliverSeq;
+ framing::ChannelId currentChannel;
+ boost::shared_ptr<broker::TxBuffer> txBuffer;
+
+ int FIXMEcredit; // FIXME aconway 2008-12-05: remove
+
+ friend std::ostream& operator<<(std::ostream&, const Connection&);
+};
+
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_CONNECTION_H*/
diff --git a/RC9/qpid/cpp/src/qpid/cluster/ConnectionCodec.cpp b/RC9/qpid/cpp/src/qpid/cluster/ConnectionCodec.cpp
new file mode 100644
index 0000000000..44e40f0591
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/ConnectionCodec.cpp
@@ -0,0 +1,82 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "ConnectionCodec.h"
+#include "Connection.h"
+#include "Cluster.h"
+#include "ProxyInputHandler.h"
+#include "qpid/broker/Connection.h"
+#include "qpid/framing/ConnectionCloseBody.h"
+#include "qpid/framing/ConnectionCloseOkBody.h"
+#include "qpid/log/Statement.h"
+#include "qpid/memory.h"
+#include <stdexcept>
+#include <boost/utility/in_place_factory.hpp>
+
+namespace qpid {
+namespace cluster {
+
+using namespace framing;
+
+sys::ConnectionCodec*
+ConnectionCodec::Factory::create(ProtocolVersion v, sys::OutputControl& out, const std::string& id) {
+ if (v == ProtocolVersion(0, 10))
+ return new ConnectionCodec(out, id, cluster, false);
+ else if (v == ProtocolVersion(0x80 + 0, 0x80 + 10))
+ return new ConnectionCodec(out, id, cluster, true); // Catch-up connection
+ return 0;
+}
+
+// Used for outgoing Link connections, we don't care.
+sys::ConnectionCodec*
+ConnectionCodec::Factory::create(sys::OutputControl& out, const std::string& id) {
+ return next->create(out, id);
+}
+
+ConnectionCodec::ConnectionCodec(sys::OutputControl& out, const std::string& id, Cluster& cluster, bool catchUp)
+ : codec(out, id, false),
+ interceptor(new Connection(cluster, codec, id, cluster.getId(), catchUp)),
+ id(interceptor->getId()),
+ localId(id)
+{
+ std::auto_ptr<sys::ConnectionInputHandler> ih(new ProxyInputHandler(interceptor));
+ codec.setInputHandler(ih);
+ if (!catchUp) // Don't put catchUp connections in the cluster map.
+ cluster.insert(interceptor);
+}
+
+ConnectionCodec::~ConnectionCodec() {}
+
+size_t ConnectionCodec::decode(const char* buffer, size_t size) {
+ QPID_LOG(trace, "RECVB [" << localId << "]: " << size << " bytes");
+ return interceptor->decode(buffer, size);
+}
+
+bool ConnectionCodec::isClosed() const { return codec.isClosed(); }
+
+size_t ConnectionCodec::encode(const char* buffer, size_t size) { return codec.encode(buffer, size); }
+
+bool ConnectionCodec::canEncode() { return codec.canEncode(); }
+
+void ConnectionCodec::closed() { codec.closed(); }
+
+ProtocolVersion ConnectionCodec::getVersion() const { return codec.getVersion(); }
+
+}} // namespace qpid::cluster
diff --git a/RC9/qpid/cpp/src/qpid/cluster/ConnectionCodec.h b/RC9/qpid/cpp/src/qpid/cluster/ConnectionCodec.h
new file mode 100644
index 0000000000..86fac270fa
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/ConnectionCodec.h
@@ -0,0 +1,80 @@
+#ifndef QPID_CLUSTER_CONNCTIONCODEC_H
+#define QPID_CLUSTER_CONNCTIONCODEC_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/amqp_0_10/Connection.h"
+#include "qpid/cluster/Connection.h"
+#include <boost/shared_ptr.hpp>
+#include <boost/intrusive_ptr.hpp>
+
+namespace qpid {
+
+namespace broker {
+class Connection;
+}
+
+namespace cluster {
+class Cluster;
+
+/**
+ * Encapsulates the standard amqp_0_10::ConnectionCodec and sets up
+ * a cluster::Connection for the connection.
+ *
+ * The ConnectionCodec is deleted by the network layer when the
+ * connection closes. The cluster::Connection needs to be kept
+ * around until all cluster business on the connection is complete.
+ *
+ */
+class ConnectionCodec : public sys::ConnectionCodec {
+ public:
+ struct Factory : public sys::ConnectionCodec::Factory {
+ boost::shared_ptr<sys::ConnectionCodec::Factory> next;
+ Cluster& cluster;
+ Factory(boost::shared_ptr<sys::ConnectionCodec::Factory> f, Cluster& c)
+ : next(f), cluster(c) {}
+ sys::ConnectionCodec* create(framing::ProtocolVersion, sys::OutputControl&, const std::string& id);
+ sys::ConnectionCodec* create(sys::OutputControl&, const std::string& id);
+ };
+
+ ConnectionCodec(sys::OutputControl& out, const std::string& id, Cluster& c, bool catchUp);
+ ~ConnectionCodec();
+
+ // ConnectionCodec functions.
+ size_t decode(const char* buffer, size_t size);
+ size_t encode(const char* buffer, size_t size);
+ bool canEncode();
+ void closed();
+ bool isClosed() const;
+ framing::ProtocolVersion getVersion() const;
+
+
+ private:
+ amqp_0_10::Connection codec;
+ boost::intrusive_ptr<cluster::Connection> interceptor;
+ cluster::ConnectionId id;
+ std::string localId;
+};
+
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_CONNCTIONCODEC_H*/
diff --git a/RC9/qpid/cpp/src/qpid/cluster/ConnectionMap.h b/RC9/qpid/cpp/src/qpid/cluster/ConnectionMap.h
new file mode 100644
index 0000000000..f1862e2e75
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/ConnectionMap.h
@@ -0,0 +1,90 @@
+#ifndef QPID_CLUSTER_CONNECTIONMAP_H
+#define QPID_CLUSTER_CONNECTIONMAP_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "types.h"
+#include "Connection.h"
+#include "ClusterMap.h"
+#include "qpid/sys/Mutex.h"
+#include <boost/intrusive_ptr.hpp>
+#include <map>
+
+namespace qpid {
+namespace cluster {
+
+/**
+ * Thread safe map of connections.
+ */
+class ConnectionMap
+{
+ public:
+ typedef boost::intrusive_ptr<cluster::Connection> ConnectionPtr;
+ typedef std::vector<ConnectionPtr> Vector;
+
+ void insert(ConnectionId id, ConnectionPtr p) {
+ ScopedLock l(lock);
+ map.insert(Map::value_type(id,p));
+ }
+
+ void erase(ConnectionId id) {
+ ScopedLock l(lock);
+ map.erase(id);
+ }
+
+ ConnectionPtr find(ConnectionId id) const {
+ ScopedLock l(lock);
+ Map::const_iterator i = map.find(id);
+ return i == map.end() ? ConnectionPtr() : i->second;
+ }
+
+ Vector values() const {
+ Vector result(map.size());
+ std::transform(map.begin(), map.end(), result.begin(),
+ boost::bind(&Map::value_type::second, _1));
+ return result;
+ }
+
+ void update(MemberId myId, const ClusterMap& cluster) {
+ for (Map::iterator i = map.begin(); i != map.end(); ) {
+ MemberId member = i->first.getMember();
+ if (member != myId && !cluster.isMember(member)) {
+ i->second->left();
+ map.erase(i++);
+ } else {
+ i++;
+ }
+ }
+ }
+
+ size_t size() const { return map.size(); }
+ private:
+ typedef std::map<ConnectionId, ConnectionPtr> Map;
+ typedef sys::Mutex::ScopedLock ScopedLock;
+
+ mutable sys::Mutex lock;
+ Map map;
+};
+
+
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_CONNECTIONMAP_H*/
diff --git a/RC9/qpid/cpp/src/qpid/cluster/Cpg.cpp b/RC9/qpid/cpp/src/qpid/cluster/Cpg.cpp
new file mode 100644
index 0000000000..48c3b483f9
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/Cpg.cpp
@@ -0,0 +1,197 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "Cpg.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/posix/PrivatePosix.h"
+#include "qpid/log/Statement.h"
+
+#include <vector>
+#include <limits>
+#include <iterator>
+
+#include <unistd.h>
+
+namespace qpid {
+namespace cluster {
+
+using namespace std;
+
+Cpg* Cpg::cpgFromHandle(cpg_handle_t handle) {
+ void* cpg=0;
+ check(cpg_context_get(handle, &cpg), "Cannot get CPG instance.");
+ if (!cpg) throw Exception("Cannot get CPG instance.");
+ return reinterpret_cast<Cpg*>(cpg);
+}
+
+// Global callback functions.
+void Cpg::globalDeliver (
+ cpg_handle_t handle,
+ struct cpg_name *group,
+ uint32_t nodeid,
+ uint32_t pid,
+ void* msg,
+ int msg_len)
+{
+ cpgFromHandle(handle)->handler.deliver(handle, group, nodeid, pid, msg, msg_len);
+}
+
+void Cpg::globalConfigChange(
+ cpg_handle_t handle,
+ struct cpg_name *group,
+ struct cpg_address *members, int nMembers,
+ struct cpg_address *left, int nLeft,
+ struct cpg_address *joined, int nJoined
+)
+{
+ cpgFromHandle(handle)->handler.configChange(handle, group, members, nMembers, left, nLeft, joined, nJoined);
+}
+
+int Cpg::getFd() {
+ int fd;
+ check(cpg_fd_get(handle, &fd), "Cannot get CPG file descriptor");
+ return fd;
+}
+
+Cpg::Cpg(Handler& h) : IOHandle(new sys::IOHandlePrivate), handler(h), isShutdown(false) {
+ cpg_callbacks_t callbacks;
+ ::memset(&callbacks, sizeof(callbacks), 0);
+ callbacks.cpg_deliver_fn = &globalDeliver;
+ callbacks.cpg_confchg_fn = &globalConfigChange;
+ check(cpg_initialize(&handle, &callbacks), "Cannot initialize CPG");
+ check(cpg_context_set(handle, this), "Cannot set CPG context");
+ // Note: CPG is currently unix-specific. If CPG is ported to
+ // windows then this needs to be refactored into
+ // qpid::sys::<platform>
+ IOHandle::impl->fd = getFd();
+ QPID_LOG(debug, "Initialized CPG handle 0x" << std::hex << handle);
+}
+
+Cpg::~Cpg() {
+ try {
+ shutdown();
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Exception in Cpg destructor: " << e.what());
+ }
+}
+
+void Cpg::join(const std::string& name) {
+ group = name;
+ check(cpg_join(handle, &group), cantJoinMsg(group));
+}
+
+void Cpg::leave() {
+ check(cpg_leave(handle, &group), cantLeaveMsg(group));
+}
+
+bool Cpg::isFlowControlEnabled() {
+ cpg_flow_control_state_t flowState;
+ check(cpg_flow_control_state_get(handle, &flowState), "Cannot get CPG flow control status.");
+ return flowState == CPG_FLOW_CONTROL_ENABLED;
+}
+
+bool Cpg::mcast(const iovec* iov, int iovLen) {
+ if (isFlowControlEnabled()) {
+ QPID_LOG(warning, "CPG flow control enabled")
+ return false;
+ }
+ cpg_error_t result;
+ do {
+ result = cpg_mcast_joined(handle, CPG_TYPE_AGREED, const_cast<iovec*>(iov), iovLen);
+ if (result != CPG_ERR_TRY_AGAIN) check(result, cantMcastMsg(group));
+ } while(result == CPG_ERR_TRY_AGAIN);
+ return true;
+}
+
+void Cpg::shutdown() {
+ if (!isShutdown) {
+ QPID_LOG(debug,"Shutting down CPG");
+ isShutdown=true;
+ check(cpg_finalize(handle), "Error in shutdown of CPG");
+ }
+}
+
+void Cpg::dispatch(cpg_dispatch_t type) {
+ check(cpg_dispatch(handle,type), "Error in CPG dispatch");
+}
+
+string Cpg::errorStr(cpg_error_t err, const std::string& msg) {
+ switch (err) {
+ case CPG_OK: return msg+": ok";
+ case CPG_ERR_LIBRARY: return msg+": library error";
+ case CPG_ERR_TIMEOUT: return msg+": timeout";
+ case CPG_ERR_TRY_AGAIN: return msg+": timeout. The aisexec daemon may not be running";
+ case CPG_ERR_INVALID_PARAM: return msg+": invalid param";
+ case CPG_ERR_NO_MEMORY: return msg+": no memory";
+ case CPG_ERR_BAD_HANDLE: return msg+": bad handle";
+ case CPG_ERR_ACCESS: return msg+": access denied.";
+ case CPG_ERR_NOT_EXIST: return msg+": not exist";
+ case CPG_ERR_EXIST: return msg+": exist";
+ case CPG_ERR_NOT_SUPPORTED: return msg+": not supported";
+ case CPG_ERR_SECURITY: return msg+": security";
+ case CPG_ERR_TOO_MANY_GROUPS: return msg+": too many groups";
+ default:
+ assert(0);
+ return ": unknown";
+ };
+}
+
+std::string Cpg::cantJoinMsg(const Name& group) {
+ return "Cannot join CPG group "+group.str();
+}
+
+std::string Cpg::cantLeaveMsg(const Name& group) {
+ return "Cannot leave CPG group "+group.str();
+}
+
+std::string Cpg::cantMcastMsg(const Name& group) {
+ return "Cannot mcast to CPG group "+group.str();
+}
+
+MemberId Cpg::self() const {
+ unsigned int nodeid;
+ check(cpg_local_get(handle, &nodeid), "Cannot get local CPG identity");
+ return MemberId(nodeid, getpid());
+}
+
+namespace { int byte(uint32_t value, int i) { return (value >> (i*8)) & 0xff; } }
+
+ostream& operator <<(ostream& out, const MemberId& id) {
+ out << byte(id.first, 0) << "."
+ << byte(id.first, 1) << "."
+ << byte(id.first, 2) << "."
+ << byte(id.first, 3);
+ return out << ":" << id.second;
+}
+
+ostream& operator<<(ostream& o, const ConnectionId& c) {
+ return o << c.first << "-" << c.second;
+}
+
+std::string MemberId::str() const {
+ char s[8];
+ reinterpret_cast<uint32_t&>(s[0]) = htonl(first);
+ reinterpret_cast<uint32_t&>(s[4]) = htonl(second);
+ return std::string(s,8);
+}
+
+MemberId::MemberId(const std::string& s) {
+ first = ntohl(reinterpret_cast<const uint32_t&>(s[0]));
+ second = ntohl(reinterpret_cast<const uint32_t&>(s[4]));
+}
+}} // namespace qpid::cluster
diff --git a/RC9/qpid/cpp/src/qpid/cluster/Cpg.h b/RC9/qpid/cpp/src/qpid/cluster/Cpg.h
new file mode 100644
index 0000000000..5de2b516d5
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/Cpg.h
@@ -0,0 +1,169 @@
+#ifndef CPG_H
+#define CPG_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/Exception.h"
+#include "qpid/cluster/Dispatchable.h"
+#include "qpid/cluster/types.h"
+#include "qpid/sys/IOHandle.h"
+#include "qpid/sys/Mutex.h"
+
+#include <boost/scoped_ptr.hpp>
+
+#include <cassert>
+#include <string.h>
+
+namespace qpid {
+namespace cluster {
+
+/**
+ * Lightweight C++ interface to cpg.h operations.
+ *
+ * Manages a single CPG handle, initialized in ctor, finialzed in destructor.
+ * On error all functions throw Cpg::Exception.
+ *
+ */
+class Cpg : public sys::IOHandle {
+ public:
+ struct Exception : public ::qpid::Exception {
+ Exception(const std::string& msg) : ::qpid::Exception(msg) {}
+ };
+
+ struct Name : public cpg_name {
+ Name() { length = 0; }
+ Name(const char* s) { copy(s, strlen(s)); }
+ Name(const char* s, size_t n) { copy(s,n); }
+ Name(const std::string& s) { copy(s.data(), s.size()); }
+ void copy(const char* s, size_t n) {
+ assert(n < CPG_MAX_NAME_LENGTH);
+ memcpy(value, s, n);
+ length=n;
+ }
+
+ std::string str() const { return std::string(value, length); }
+ };
+
+ static std::string str(const cpg_name& n) {
+ return std::string(n.value, n.length);
+ }
+
+ struct Handler {
+ virtual ~Handler() {};
+ virtual void deliver(
+ cpg_handle_t /*handle*/,
+ struct cpg_name *group,
+ uint32_t /*nodeid*/,
+ uint32_t /*pid*/,
+ void* /*msg*/,
+ int /*msg_len*/) = 0;
+
+ virtual void configChange(
+ cpg_handle_t /*handle*/,
+ struct cpg_name */*group*/,
+ struct cpg_address */*members*/, int /*nMembers*/,
+ struct cpg_address */*left*/, int /*nLeft*/,
+ struct cpg_address */*joined*/, int /*nJoined*/
+ ) = 0;
+ };
+
+ /** Open a CPG handle.
+ *@param handler for CPG events.
+ */
+ Cpg(Handler&);
+
+ /** Destructor calls shutdown if not already calledx. */
+ ~Cpg();
+
+ /** Disconnect from CPG */
+ void shutdown();
+
+ /** Dispatch CPG events.
+ *@param type one of
+ * - CPG_DISPATCH_ONE - dispatch exactly one event.
+ * - CPG_DISPATCH_ALL - dispatch all available events, don't wait.
+ * - CPG_DISPATCH_BLOCKING - blocking dispatch loop.
+ */
+ void dispatch(cpg_dispatch_t type);
+
+ void dispatchOne() { dispatch(CPG_DISPATCH_ONE); }
+ void dispatchAll() { dispatch(CPG_DISPATCH_ALL); }
+ void dispatchBlocking() { dispatch(CPG_DISPATCH_BLOCKING); }
+
+ void join(const std::string& group);
+ void leave();
+
+ /** Multicast to the group. NB: must not be called concurrently.
+ *
+ *@return true if the message was multi-cast, false if
+ * it was not sent due to flow control.
+ */
+ bool mcast(const iovec* iov, int iovLen);
+
+ cpg_handle_t getHandle() const { return handle; }
+
+ MemberId self() const;
+
+ int getFd();
+
+ bool isFlowControlEnabled();
+
+ private:
+ static std::string errorStr(cpg_error_t err, const std::string& msg);
+ static std::string cantJoinMsg(const Name&);
+ static std::string cantLeaveMsg(const Name&);
+ static std::string cantMcastMsg(const Name&);
+
+ static void check(cpg_error_t result, const std::string& msg) {
+ if (result != CPG_OK) throw Exception(errorStr(result, msg));
+ }
+
+ static Cpg* cpgFromHandle(cpg_handle_t);
+
+ static void globalDeliver(
+ cpg_handle_t handle,
+ struct cpg_name *group,
+ uint32_t nodeid,
+ uint32_t pid,
+ void* msg,
+ int msg_len);
+
+ static void globalConfigChange(
+ cpg_handle_t handle,
+ struct cpg_name *group,
+ struct cpg_address *members, int nMembers,
+ struct cpg_address *left, int nLeft,
+ struct cpg_address *joined, int nJoined
+ );
+
+ cpg_handle_t handle;
+ Handler& handler;
+ bool isShutdown;
+ Name group;
+ sys::Mutex dispatchLock;
+};
+
+inline bool operator==(const cpg_name& a, const cpg_name& b) {
+ return a.length==b.length && strncmp(a.value, b.value, a.length) == 0;
+}
+inline bool operator!=(const cpg_name& a, const cpg_name& b) { return !(a == b); }
+
+}} // namespace qpid::cluster
+
+#endif /*!CPG_H*/
diff --git a/RC9/qpid/cpp/src/qpid/cluster/Dispatchable.h b/RC9/qpid/cpp/src/qpid/cluster/Dispatchable.h
new file mode 100644
index 0000000000..e7f0df4218
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/Dispatchable.h
@@ -0,0 +1,52 @@
+#ifndef QPID_CLUSTER_DISPATCHABLE_H
+#define QPID_CLUSTER_DISPATCHABLE_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace qpid {
+namespace cluster {
+
+/**
+ * Interface for classes that have some "events" that need dispatching
+ * in a thread.
+ */
+class Dispatchable
+{
+ public:
+ virtual ~Dispatchable() {}
+
+ /** Dispatch one event in current thread. */
+ virtual void dispatchOne() = 0;
+ /** Dispatch all available events, don't block. */
+ virtual void dispatchAll() = 0;
+ /** Blocking loop to dispatch cluster events */
+ virtual void dispatchBlocking() = 0;
+
+ /** Wait for at least one event, then dispatch all available events.
+ * Don't block. Useful for tests.
+ */
+ virtual void dispatchSome() { dispatchOne(); dispatchAll(); }
+
+};
+
+}} // namespace qpid::cluster
+
+
+
+#endif /*!QPID_CLUSTER_DISPATCHABLE_H*/
diff --git a/RC9/qpid/cpp/src/qpid/cluster/DumpClient.cpp b/RC9/qpid/cpp/src/qpid/cluster/DumpClient.cpp
new file mode 100644
index 0000000000..3f3212470d
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/DumpClient.cpp
@@ -0,0 +1,369 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "DumpClient.h"
+#include "Cluster.h"
+#include "ClusterMap.h"
+#include "Connection.h"
+#include "qpid/client/SessionBase_0_10Access.h"
+#include "qpid/client/ConnectionAccess.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/broker/Queue.h"
+#include "qpid/broker/QueueRegistry.h"
+#include "qpid/broker/Message.h"
+#include "qpid/broker/Exchange.h"
+#include "qpid/broker/ExchangeRegistry.h"
+#include "qpid/broker/SessionHandler.h"
+#include "qpid/broker/SessionState.h"
+#include "qpid/broker/TxOpVisitor.h"
+#include "qpid/broker/DtxAck.h"
+#include "qpid/broker/TxAccept.h"
+#include "qpid/broker/TxPublish.h"
+#include "qpid/broker/RecoveredDequeue.h"
+#include "qpid/broker/RecoveredEnqueue.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/framing/ClusterConnectionMembershipBody.h"
+#include "qpid/framing/ClusterConnectionShadowReadyBody.h"
+#include "qpid/framing/ClusterConnectionSessionStateBody.h"
+#include "qpid/framing/ClusterConnectionConsumerStateBody.h"
+#include "qpid/framing/enum.h"
+#include "qpid/framing/ProtocolVersion.h"
+#include "qpid/framing/TypeCode.h"
+#include "qpid/log/Statement.h"
+#include "qpid/Url.h"
+#include <boost/bind.hpp>
+#include <algorithm>
+
+namespace qpid {
+namespace cluster {
+
+using broker::Broker;
+using broker::Exchange;
+using broker::Queue;
+using broker::QueueBinding;
+using broker::Message;
+using namespace framing;
+namespace arg=client::arg;
+using client::SessionBase_0_10Access;
+
+struct ClusterConnectionProxy : public AMQP_AllProxy::ClusterConnection {
+ ClusterConnectionProxy(client::Connection c) :
+ AMQP_AllProxy::ClusterConnection(*client::ConnectionAccess::getImpl(c)) {}
+ ClusterConnectionProxy(client::AsyncSession s) :
+ AMQP_AllProxy::ClusterConnection(SessionBase_0_10Access(s).get()->out) {}
+};
+
+// Create a connection with special version that marks it as a catch-up connection.
+client::Connection catchUpConnection() {
+ client::Connection c;
+ client::ConnectionAccess::setVersion(c, ProtocolVersion(0x80 , 0x80 + 10));
+ return c;
+}
+
+// Send a control body directly to the session.
+void send(client::AsyncSession& s, const AMQBody& body) {
+ client::SessionBase_0_10Access sb(s);
+ sb.get()->send(body);
+}
+
+// TODO aconway 2008-09-24: optimization: dump connections/sessions in parallel.
+
+DumpClient::DumpClient(const MemberId& dumper, const MemberId& dumpee, const Url& url,
+ broker::Broker& broker, const ClusterMap& m, const Cluster::Connections& cons,
+ const boost::function<void()>& ok,
+ const boost::function<void(const std::exception&)>& fail)
+ : dumperId(dumper), dumpeeId(dumpee), dumpeeUrl(url), dumperBroker(broker), map(m), connections(cons),
+ connection(catchUpConnection()), shadowConnection(catchUpConnection()),
+ done(ok), failed(fail)
+{
+ connection.open(url);
+ session = connection.newSession("dump_shared");
+}
+
+DumpClient::~DumpClient() {}
+
+// Illegal exchange/queue name for catch-up, avoid clashes with user queues/exchanges.
+static const char DUMP_CHARS[] = "\000qpid-dump";
+const std::string DumpClient::DUMP(DUMP_CHARS, sizeof(DUMP_CHARS));
+
+void DumpClient::dump() {
+ QPID_LOG(debug, dumperId << " dumping state to " << dumpeeId << " at " << dumpeeUrl);
+ Broker& b = dumperBroker;
+ b.getExchanges().eachExchange(boost::bind(&DumpClient::dumpExchange, this, _1));
+
+ // Dump exchange is used to route messages to the proper queue without modifying routing key.
+ session.exchangeDeclare(arg::exchange=DUMP, arg::type="fanout", arg::autoDelete=true);
+ b.getQueues().eachQueue(boost::bind(&DumpClient::dumpQueue, this, _1));
+ // Dump queue is used to transfer acquired messages that are no longer on their original queue.
+ session.queueDeclare(arg::queue=DUMP, arg::autoDelete=true);
+ session.sync();
+ session.close();
+
+ std::for_each(connections.begin(), connections.end(), boost::bind(&DumpClient::dumpConnection, this, _1));
+ AMQFrame frame(map.asMethodBody());
+ client::ConnectionAccess::getImpl(connection)->handle(frame);
+ connection.close();
+ QPID_LOG(debug, dumperId << " dumped state to " << dumpeeId << " at " << dumpeeUrl);
+}
+
+void DumpClient::run() {
+ try {
+ dump();
+ done();
+ } catch (const std::exception& e) {
+ failed(e);
+ }
+ delete this;
+}
+
+namespace {
+template <class T> std::string encode(const T& t) {
+ std::string encoded;
+ encoded.resize(t.encodedSize());
+ framing::Buffer buf(const_cast<char*>(encoded.data()), encoded.size());
+ t.encode(buf);
+ return encoded;
+}
+} // namespace
+
+void DumpClient::dumpExchange(const boost::shared_ptr<Exchange>& ex) {
+ QPID_LOG(debug, dumperId << " dumping exchange " << ex->getName());
+ ClusterConnectionProxy proxy(session);
+ proxy.exchange(encode(*ex));
+}
+
+/** Bind a queue to the dump exchange and dump messges to it
+ * setting the message possition as needed.
+ */
+class MessageDumper {
+ std::string queue;
+ bool haveLastPos;
+ framing::SequenceNumber lastPos;
+ client::AsyncSession session;
+
+ public:
+
+ MessageDumper(const string& q, const client::AsyncSession s) : queue(q), haveLastPos(false), session(s) {
+ session.exchangeBind(queue, DumpClient::DUMP);
+ }
+
+ ~MessageDumper() {
+ session.exchangeUnbind(queue, DumpClient::DUMP);
+ }
+
+ void dumpQueuedMessage(const broker::QueuedMessage& message) {
+ if (!haveLastPos || message.position - lastPos != 1) {
+ ClusterConnectionProxy(session).queuePosition(queue, message.position.getValue()-1);
+ haveLastPos = true;
+ }
+ lastPos = message.position;
+ SessionBase_0_10Access sb(session);
+ framing::MessageTransferBody transfer(
+ framing::ProtocolVersion(), DumpClient::DUMP, message::ACCEPT_MODE_NONE, message::ACQUIRE_MODE_PRE_ACQUIRED);
+ sb.get()->send(transfer, message.payload->getFrames());
+ }
+
+ void dumpMessage(const boost::intrusive_ptr<broker::Message>& message) {
+ dumpQueuedMessage(broker::QueuedMessage(0, message, haveLastPos? lastPos.getValue()+1 : 1));
+ }
+};
+
+
+void DumpClient::dumpQueue(const boost::shared_ptr<Queue>& q) {
+ QPID_LOG(debug, dumperId << " dumping queue " << q->getName());
+ ClusterConnectionProxy proxy(session);
+ proxy.queue(encode(*q));
+ MessageDumper dumper(q->getName(), session);
+ q->eachMessage(boost::bind(&MessageDumper::dumpQueuedMessage, &dumper, _1));
+ q->eachBinding(boost::bind(&DumpClient::dumpBinding, this, q->getName(), _1));
+}
+
+
+void DumpClient::dumpBinding(const std::string& queue, const QueueBinding& binding) {
+ session.exchangeBind(queue, binding.exchange, binding.key, binding.args);
+}
+
+void DumpClient::dumpConnection(const boost::intrusive_ptr<Connection>& dumpConnection) {
+ QPID_LOG(debug, dumperId << " dumping connection " << *dumpConnection);
+ shadowConnection = catchUpConnection();
+
+ broker::Connection& bc = dumpConnection->getBrokerConnection();
+ // FIXME aconway 2008-10-20: What authentication info to use on reconnect?
+ shadowConnection.open(dumpeeUrl, bc.getUserId(), ""/*password*/, "/"/*vhost*/, bc.getFrameMax());
+ bc.eachSessionHandler(boost::bind(&DumpClient::dumpSession, this, _1));
+ ClusterConnectionProxy(shadowConnection).shadowReady(
+ dumpConnection->getId().getMember(),
+ reinterpret_cast<uint64_t>(dumpConnection->getId().getPointer()));
+ shadowConnection.close();
+ QPID_LOG(debug, dumperId << " dumped connection " << *dumpConnection);
+}
+
+void DumpClient::dumpSession(broker::SessionHandler& sh) {
+ QPID_LOG(debug, dumperId << " dumping session " << &sh.getConnection() << "[" << sh.getChannel() << "] = "
+ << sh.getSession()->getId());
+ broker::SessionState* ss = sh.getSession();
+ if (!ss) return; // no session.
+
+ // Create a client session to dump session state.
+ boost::shared_ptr<client::ConnectionImpl> cimpl = client::ConnectionAccess::getImpl(shadowConnection);
+ boost::shared_ptr<client::SessionImpl> simpl = cimpl->newSession(ss->getId().getName(), ss->getTimeout(), sh.getChannel());
+ client::SessionBase_0_10Access(shadowSession).set(simpl);
+ AMQP_AllProxy::ClusterConnection proxy(simpl->out);
+
+ // Re-create session state on remote connection.
+
+ // Dump consumers. For reasons unknown, boost::bind does not work here with boost 1.33.
+ QPID_LOG(debug, dumperId << " dumping consumers.");
+ ss->getSemanticState().eachConsumer(std::bind1st(std::mem_fun(&DumpClient::dumpConsumer),this));
+
+ QPID_LOG(debug, dumperId << " dumping unacknowledged messages.");
+ broker::DeliveryRecords& drs = ss->getSemanticState().getUnacked();
+ std::for_each(drs.begin(), drs.end(), boost::bind(&DumpClient::dumpUnacked, this, _1));
+
+ dumpTxState(ss->getSemanticState()); // Tx transaction state.
+
+ // Adjust for command counter for message in progress, will be sent after state update.
+ boost::intrusive_ptr<Message> inProgress = ss->getMessageInProgress();
+ SequenceNumber received = ss->receiverGetReceived().command;
+ if (inProgress)
+ --received;
+
+ // Reset command-sequence state.
+ proxy.sessionState(
+ ss->senderGetReplayPoint().command,
+ ss->senderGetCommandPoint().command,
+ ss->senderGetIncomplete(),
+ std::max(received, ss->receiverGetExpected().command),
+ received,
+ ss->receiverGetUnknownComplete(),
+ ss->receiverGetIncomplete()
+ );
+
+ // Send frames for partial message in progress.
+ if (inProgress) {
+ inProgress->getFrames().map(simpl->out);
+ }
+
+ // FIXME aconway 2008-09-23: update session replay list.
+
+ QPID_LOG(debug, dumperId << " dumped session " << sh.getSession()->getId());
+}
+
+void DumpClient::dumpConsumer(const broker::SemanticState::ConsumerImpl* ci) {
+ QPID_LOG(debug, dumperId << " dumping consumer " << ci->getName() << " on " << shadowSession.getId());
+ using namespace message;
+ shadowSession.messageSubscribe(
+ arg::queue = ci->getQueue()->getName(),
+ arg::destination = ci->getName(),
+ arg::acceptMode = ci->isAckExpected() ? ACCEPT_MODE_EXPLICIT : ACCEPT_MODE_NONE,
+ arg::acquireMode = ci->isAcquire() ? ACQUIRE_MODE_PRE_ACQUIRED : ACQUIRE_MODE_NOT_ACQUIRED,
+ arg::exclusive = ci->isExclusive(),
+ arg::resumeId = ci->getResumeId(),
+ arg::resumeTtl = ci->getResumeTtl(),
+ arg::arguments = ci->getArguments()
+ );
+ shadowSession.messageSetFlowMode(ci->getName(), ci->isWindowing() ? FLOW_MODE_WINDOW : FLOW_MODE_CREDIT);
+ shadowSession.messageFlow(ci->getName(), CREDIT_UNIT_MESSAGE, ci->getMsgCredit());
+ shadowSession.messageFlow(ci->getName(), CREDIT_UNIT_BYTE, ci->getByteCredit());
+ ClusterConnectionConsumerStateBody state(
+ ProtocolVersion(),
+ ci->getName(),
+ ci->isBlocked(),
+ ci->isNotifyEnabled()
+ );
+ client::SessionBase_0_10Access(shadowSession).get()->send(state);
+ QPID_LOG(debug, dumperId << " dumped consumer " << ci->getName() << " on " << shadowSession.getId());
+}
+
+void DumpClient::dumpUnacked(const broker::DeliveryRecord& dr) {
+ if (!dr.isEnded() && dr.isAcquired() && dr.getMessage().payload) {
+ // If the message is acquired then it is no longer on the
+ // dumpees queue, put it on the dump queue for dumpee to pick up.
+ //
+ MessageDumper(DUMP, shadowSession).dumpQueuedMessage(dr.getMessage());
+ }
+ ClusterConnectionProxy(shadowSession).deliveryRecord(
+ dr.getQueue()->getName(),
+ dr.getMessage().position,
+ dr.getTag(),
+ dr.getId(),
+ dr.isAcquired(),
+ dr.isAccepted(),
+ dr.isCancelled(),
+ dr.isComplete(),
+ dr.isEnded(),
+ dr.isWindowing(),
+ dr.getCredit()
+ );
+}
+
+class TxOpDumper : public broker::TxOpConstVisitor, public MessageDumper {
+ public:
+ TxOpDumper(DumpClient& dc, client::AsyncSession s)
+ : MessageDumper(DumpClient::DUMP, s), parent(dc), session(s), proxy(s) {}
+
+ void operator()(const broker::DtxAck& ) {
+ throw InternalErrorException("DTX transactions not currently supported by cluster.");
+ }
+
+ void operator()(const broker::RecoveredDequeue& rdeq) {
+ dumpMessage(rdeq.getMessage());
+ proxy.txEnqueue(rdeq.getQueue()->getName());
+ }
+
+ void operator()(const broker::RecoveredEnqueue& renq) {
+ dumpMessage(renq.getMessage());
+ proxy.txEnqueue(renq.getQueue()->getName());
+ }
+
+ void operator()(const broker::TxAccept& txAccept) {
+ proxy.txAccept(txAccept.getAcked());
+ }
+
+ void operator()(const broker::TxPublish& txPub) {
+ dumpMessage(txPub.getMessage());
+ typedef std::list<Queue::shared_ptr> QueueList;
+ const QueueList& qlist = txPub.getQueues();
+ Array qarray(TYPE_CODE_STR8);
+ for (QueueList::const_iterator i = qlist.begin(); i != qlist.end(); ++i)
+ qarray.push_back(Array::ValuePtr(new Str8Value((*i)->getName())));
+ proxy.txPublish(qarray, txPub.delivered);
+ }
+
+ private:
+ DumpClient& parent;
+ client::AsyncSession session;
+ ClusterConnectionProxy proxy;
+};
+
+void DumpClient::dumpTxState(broker::SemanticState& s) {
+ QPID_LOG(debug, dumperId << " dumping TX transaction state.");
+ ClusterConnectionProxy proxy(shadowSession);
+ proxy.accumulatedAck(s.getAccumulatedAck());
+ broker::TxBuffer::shared_ptr txBuffer = s.getTxBuffer();
+ if (txBuffer) {
+ proxy.txStart();
+ TxOpDumper dumper(*this, shadowSession);
+ txBuffer->accept(dumper);
+ proxy.txEnd();
+ }
+}
+
+}} // namespace qpid::cluster
diff --git a/RC9/qpid/cpp/src/qpid/cluster/DumpClient.h b/RC9/qpid/cpp/src/qpid/cluster/DumpClient.h
new file mode 100644
index 0000000000..23676e7646
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/DumpClient.h
@@ -0,0 +1,101 @@
+#ifndef QPID_CLUSTER_DUMPCLIENT_H
+#define QPID_CLUSTER_DUMPCLIENT_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "ClusterMap.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/AsyncSession.h"
+#include "qpid/broker/SemanticState.h"
+#include "qpid/sys/Runnable.h"
+#include <boost/shared_ptr.hpp>
+
+
+namespace qpid {
+
+class Url;
+
+namespace broker {
+
+class Broker;
+class Queue;
+class Exchange;
+class QueueBindings;
+class QueueBinding;
+class QueuedMessage;
+class SessionHandler;
+class DeliveryRecord;
+class SessionState;
+class SemanticState;
+
+} // namespace broker
+
+namespace cluster {
+
+class Cluster;
+class Connection;
+class ClusterMap;
+
+/**
+ * A client that dumps the contents of a local broker to a remote one using AMQP.
+ */
+class DumpClient : public sys::Runnable {
+ public:
+ static const std::string DUMP; // Name for special dump queue and exchange.
+
+ DumpClient(const MemberId& dumper, const MemberId& dumpee, const Url&,
+ broker::Broker& donor, const ClusterMap& map, const std::vector<boost::intrusive_ptr<Connection> >& ,
+ const boost::function<void()>& done,
+ const boost::function<void(const std::exception&)>& fail);
+
+ ~DumpClient();
+ void dump();
+ void run(); // Will delete this when finished.
+
+ void dumpUnacked(const broker::DeliveryRecord&);
+
+ private:
+ void dumpQueue(const boost::shared_ptr<broker::Queue>&);
+ void dumpExchange(const boost::shared_ptr<broker::Exchange>&);
+ void dumpMessage(const broker::QueuedMessage&);
+ void dumpMessageTo(const broker::QueuedMessage&, const std::string& queue, client::Session s);
+ void dumpBinding(const std::string& queue, const broker::QueueBinding& binding);
+ void dumpConnection(const boost::intrusive_ptr<Connection>& connection);
+ void dumpSession(broker::SessionHandler& s);
+ void dumpTxState(broker::SemanticState& s);
+ void dumpConsumer(const broker::SemanticState::ConsumerImpl*);
+
+ MemberId dumperId;
+ MemberId dumpeeId;
+ Url dumpeeUrl;
+ broker::Broker& dumperBroker;
+ ClusterMap map;
+ std::vector<boost::intrusive_ptr<Connection> > connections;
+ client::Connection connection, shadowConnection;
+ client::AsyncSession session, shadowSession;
+ boost::function<void()> done;
+ boost::function<void(const std::exception& e)> failed;
+};
+
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_DUMPCLIENT_H*/
diff --git a/RC9/qpid/cpp/src/qpid/cluster/Event.cpp b/RC9/qpid/cpp/src/qpid/cluster/Event.cpp
new file mode 100644
index 0000000000..cfa8fe05f1
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/Event.cpp
@@ -0,0 +1,89 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "types.h"
+#include "Event.h"
+#include "Cpg.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/framing/AMQFrame.h"
+#include <ostream>
+#include <iterator>
+#include <algorithm>
+
+namespace qpid {
+namespace cluster {
+
+using framing::Buffer;
+
+const size_t Event::HEADER_SIZE =
+ sizeof(uint8_t) + // type
+ sizeof(uint64_t) + // connection pointer only, CPG provides member ID.
+ sizeof(uint32_t); // payload size
+
+Event::Event(EventType t, const ConnectionId& c, size_t s)
+ : type(t), connectionId(c), size(s), store(RefCountedBuffer::create(s+HEADER_SIZE)) {
+ encodeHeader();
+}
+
+Event Event::decode(const MemberId& m, framing::Buffer& buf) {
+ if (buf.available() <= HEADER_SIZE)
+ throw ClusterLeaveException("Not enough for multicast header");
+ EventType type((EventType)buf.getOctet());
+ if(type != DATA && type != CONTROL)
+ throw ClusterLeaveException("Invalid multicast event type");
+ ConnectionId connection(m, reinterpret_cast<Connection*>(buf.getLongLong()));
+ uint32_t size = buf.getLong();
+ Event e(type, connection, size);
+ if (buf.available() < size)
+ throw ClusterLeaveException("Not enough data for multicast event");
+ memcpy(e.getData(), buf.getPointer() + buf.getPosition(), size);
+ return e;
+}
+
+Event Event::control(const framing::AMQBody& body, const ConnectionId& cid) {
+ framing::AMQFrame f(body);
+ Event e(CONTROL, cid, f.encodedSize());
+ Buffer buf(e);
+ f.encode(buf);
+ return e;
+}
+
+void Event::encodeHeader () {
+ Buffer b(getStore(), HEADER_SIZE);
+ b.putOctet(type);
+ b.putLongLong(reinterpret_cast<uint64_t>(connectionId.getPointer()));
+ b.putLong(size);
+ assert(b.getPosition() == HEADER_SIZE);
+}
+
+Event::operator Buffer() const {
+ return Buffer(const_cast<char*>(getData()), getSize());
+}
+
+static const char* EVENT_TYPE_NAMES[] = { "data", "control" };
+
+std::ostream& operator << (std::ostream& o, const Event& e) {
+ o << "[event " << e.getConnectionId()
+ << " " << EVENT_TYPE_NAMES[e.getType()]
+ << " " << e.getSize() << " bytes]";
+ return o;
+}
+
+}} // namespace qpid::cluster
diff --git a/RC9/qpid/cpp/src/qpid/cluster/Event.h b/RC9/qpid/cpp/src/qpid/cluster/Event.h
new file mode 100644
index 0000000000..427410923b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/Event.h
@@ -0,0 +1,87 @@
+#ifndef QPID_CLUSTER_EVENT_H
+#define QPID_CLUSTER_EVENT_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "types.h"
+#include "Cpg.h"
+#include "Connection.h"
+#include "qpid/RefCountedBuffer.h"
+#include "qpid/framing/Buffer.h"
+#include <iosfwd>
+
+namespace qpid {
+namespace cluster {
+
+// TODO aconway 2008-09-03: more efficient solution for shared
+// byte-stream data.
+//
+
+/**
+ * Events are sent to/received from the cluster.
+ * Refcounted so they can be stored on queues.
+ */
+class Event {
+ public:
+ /** Create an event with a buffer that can hold size bytes plus an event header. */
+ Event(EventType t=DATA, const ConnectionId& c=ConnectionId(), size_t size=0);
+
+ /** Create an event copied from delivered data. */
+ static Event decode(const MemberId& m, framing::Buffer&);
+
+ /** Create an event containing a control */
+ static Event control(const framing::AMQBody&, const ConnectionId&);
+
+ EventType getType() const { return type; }
+ ConnectionId getConnectionId() const { return connectionId; }
+ MemberId getMemberId() const { return connectionId.getMember(); }
+ size_t getSize() const { return size; }
+
+ // Data excluding header.
+ char* getData() { return store + HEADER_SIZE; }
+ const char* getData() const { return store + HEADER_SIZE; }
+
+ // Store including header
+ char* getStore() { return store; }
+ const char* getStore() const { return store; }
+ size_t getStoreSize() { return size + HEADER_SIZE; }
+
+ bool isCluster() const { return connectionId.getPointer() == 0; }
+ bool isConnection() const { return connectionId.getPointer() != 0; }
+
+ operator framing::Buffer() const;
+
+ private:
+ static const size_t HEADER_SIZE;
+
+ void encodeHeader();
+
+ EventType type;
+ ConnectionId connectionId;
+ size_t size;
+ RefCountedBuffer::pointer store;
+};
+
+std::ostream& operator << (std::ostream&, const Event&);
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_EVENT_H*/
diff --git a/RC9/qpid/cpp/src/qpid/cluster/FailoverExchange.cpp b/RC9/qpid/cpp/src/qpid/cluster/FailoverExchange.cpp
new file mode 100644
index 0000000000..abc7f5df6f
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/FailoverExchange.cpp
@@ -0,0 +1,99 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "FailoverExchange.h"
+#include "qpid/broker/Message.h"
+#include "qpid/broker/DeliverableMessage.h"
+#include "qpid/broker/Queue.h"
+#include "qpid/framing/MessageProperties.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/AMQHeaderBody.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/log/Statement.h"
+#include "qpid/framing/Array.h"
+#include <boost/bind.hpp>
+#include <algorithm>
+
+namespace qpid {
+namespace cluster {
+using namespace std;
+
+using namespace broker;
+using namespace framing;
+
+const string FailoverExchange::TYPE_NAME("amq.failover");
+
+FailoverExchange::FailoverExchange(management::Manageable* parent) : Exchange(TYPE_NAME, parent) {
+ if (mgmtExchange != 0)
+ mgmtExchange->set_type(TYPE_NAME);
+}
+
+
+void FailoverExchange::setUrls(const vector<Url>& u) {
+ Lock l(lock);
+ urls=u;
+ if (urls.empty()) return;
+ std::for_each(queues.begin(), queues.end(),
+ boost::bind(&FailoverExchange::sendUpdate, this, _1));
+}
+
+string FailoverExchange::getType() const { return TYPE_NAME; }
+
+bool FailoverExchange::bind(Queue::shared_ptr queue, const string&, const framing::FieldTable*) {
+ Lock l(lock);
+ sendUpdate(queue);
+ return queues.insert(queue).second;
+}
+
+bool FailoverExchange::unbind(Queue::shared_ptr queue, const string&, const framing::FieldTable*) {
+ Lock l(lock);
+ return queues.erase(queue);
+}
+
+bool FailoverExchange::isBound(Queue::shared_ptr queue, const string* const, const framing::FieldTable*) {
+ Lock l(lock);
+ return queues.find(queue) != queues.end();
+}
+
+void FailoverExchange::route(Deliverable&, const string& , const framing::FieldTable* ) {
+ QPID_LOG(warning, "Message received by exchange " << TYPE_NAME << " ignoring");
+}
+
+void FailoverExchange::sendUpdate(const Queue::shared_ptr& queue) {
+ // Called with lock held.
+ if (urls.empty()) return;
+ framing::Array array(0x95); // FIXME aconway 2008-10-06: Array is unusable like this. Need type constants or better mapping.
+ for (Urls::const_iterator i = urls.begin(); i != urls.end(); ++i)
+ array.add(boost::shared_ptr<Str16Value>(new Str16Value(i->str())));
+ const ProtocolVersion v;
+ boost::intrusive_ptr<Message> msg(new Message);
+ AMQFrame command(MessageTransferBody(v, TYPE_NAME, 1, 0));
+ command.setLastSegment(false);
+ msg->getFrames().append(command);
+ AMQHeaderBody header;
+ header.get<MessageProperties>(true)->setContentLength(0);
+ header.get<MessageProperties>(true)->getApplicationHeaders().setArray(TYPE_NAME, array);
+ AMQFrame headerFrame(header);
+ headerFrame.setFirstSegment(false);
+ msg->getFrames().append(headerFrame);
+ DeliverableMessage(msg).deliverTo(queue);
+}
+
+}} // namespace cluster
diff --git a/RC9/qpid/cpp/src/qpid/cluster/FailoverExchange.h b/RC9/qpid/cpp/src/qpid/cluster/FailoverExchange.h
new file mode 100644
index 0000000000..738cd2a602
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/FailoverExchange.h
@@ -0,0 +1,68 @@
+#ifndef QPID_CLUSTER_FAILOVEREXCHANGE_H
+#define QPID_CLUSTER_FAILOVEREXCHANGE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/broker/Exchange.h"
+#include "qpid/broker/DeliverableMessage.h"
+#include "qpid/Url.h"
+
+#include <vector>
+#include <set>
+
+namespace qpid {
+namespace cluster {
+
+/**
+ * Failover exchange provides failover host list, as specified in AMQP 0-10.
+ */
+class FailoverExchange : public broker::Exchange
+{
+ public:
+ static const std::string TYPE_NAME;
+
+ FailoverExchange(management::Manageable* parent);
+
+ void setUrls(const std::vector<Url>&);
+
+ // Exchange overrides
+ std::string getType() const;
+ bool bind(broker::Queue::shared_ptr queue, const std::string& routingKey, const framing::FieldTable* args);
+ bool unbind(broker::Queue::shared_ptr queue, const std::string& routingKey, const framing::FieldTable* args);
+ bool isBound(broker::Queue::shared_ptr queue, const std::string* const routingKey, const framing::FieldTable* const args);
+ void route(broker::Deliverable& msg, const std::string& routingKey, const framing::FieldTable* args);
+
+ private:
+ void sendUpdate(const broker::Queue::shared_ptr&);
+
+ typedef sys::Mutex::ScopedLock Lock;
+ typedef std::vector<Url> Urls;
+ typedef std::set<broker::Queue::shared_ptr> Queues;
+
+ sys::Mutex lock;
+ Urls urls;
+ Queues queues;
+
+};
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_FAILOVEREXCHANGE_H*/
diff --git a/RC9/qpid/cpp/src/qpid/cluster/Multicaster.cpp b/RC9/qpid/cpp/src/qpid/cluster/Multicaster.cpp
new file mode 100644
index 0000000000..37d2f81b39
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/Multicaster.cpp
@@ -0,0 +1,84 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Multicaster.h"
+#include "Cpg.h"
+#include "ClusterLeaveException.h"
+#include "qpid/log/Statement.h"
+
+
+namespace qpid {
+namespace cluster {
+
+Multicaster::Multicaster(Cpg& cpg_, const boost::shared_ptr<sys::Poller>& poller) :
+ cpg(cpg_), queue(boost::bind(&Multicaster::sendMcast, this, _1), poller),
+ holding(true)
+{
+ queue.start();
+}
+
+void Multicaster::mcastControl(const framing::AMQBody& body, const ConnectionId& id) {
+ mcast(Event::control(body, id));
+}
+
+void Multicaster::mcastBuffer(const char* data, size_t size, const ConnectionId& id) {
+ Event e(DATA, id, size);
+ memcpy(e.getData(), data, size);
+ mcast(e);
+}
+
+void Multicaster::mcast(const Event& e) {
+ {
+ sys::Mutex::ScopedLock l(lock);
+ if (e.getType() == DATA && e.isConnection() && holding) {
+ holdingQueue.push_back(e);
+ QPID_LOG(trace, " MCAST held: " << e );
+ return;
+ }
+ }
+ queue.push(e);
+}
+
+
+void Multicaster::sendMcast(PollableEventQueue::Queue& values) {
+ try {
+ PollableEventQueue::Queue::iterator i = values.begin();
+ while( i != values.end()) {
+ iovec iov = { const_cast<char*>(i->getStore()), i->getStoreSize() };
+ if (!cpg.mcast(&iov, 1)) break; // returns false for flow control
+ QPID_LOG(trace, " MCAST " << *i);
+ ++i;
+ }
+ values.erase(values.begin(), i);
+ }
+ catch (const std::exception& e) {
+ throw ClusterLeaveException(e.what());
+ }
+}
+
+void Multicaster::release() {
+ sys::Mutex::ScopedLock l(lock);
+ holding = false;
+ std::for_each(holdingQueue.begin(), holdingQueue.end(), boost::bind(&Multicaster::mcast, this, _1));
+ holdingQueue.clear();
+}
+
+}} // namespace qpid::cluster
diff --git a/RC9/qpid/cpp/src/qpid/cluster/Multicaster.h b/RC9/qpid/cpp/src/qpid/cluster/Multicaster.h
new file mode 100644
index 0000000000..8b306ce10e
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/Multicaster.h
@@ -0,0 +1,71 @@
+#ifndef QPID_CLUSTER_MULTICASTER_H
+#define QPID_CLUSTER_MULTICASTER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "types.h"
+#include "Event.h"
+#include "qpid/sys/PollableQueue.h"
+#include "qpid/sys/Mutex.h"
+#include <boost/shared_ptr.hpp>
+#include <sys/uio.h> // For iovec
+
+namespace qpid {
+
+namespace sys {
+class Poller;
+}
+
+namespace cluster {
+
+class Cpg;
+
+/**
+ * Multicast to the cluster. Shared, thread safe object.
+ */
+class Multicaster
+{
+ public:
+ /** Starts in holding mode: connection data events are held, other events are mcast */
+ Multicaster(Cpg& cpg_, const boost::shared_ptr<sys::Poller>& );
+ void mcastControl(const framing::AMQBody& controlBody, const ConnectionId&);
+ void mcastBuffer(const char*, size_t, const ConnectionId&);
+ void mcast(const Event& e);
+ /** End holding mode, held events are mcast */
+ void release();
+
+ private:
+ typedef sys::PollableQueue<Event> PollableEventQueue;
+ typedef std::deque<Event> PlainEventQueue;
+
+ void sendMcast(PollableEventQueue::Queue& );
+
+ sys::Mutex lock;
+ Cpg& cpg;
+ PollableEventQueue queue;
+ bool holding;
+ PlainEventQueue holdingQueue;
+ std::vector<struct ::iovec> ioVector;
+};
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_MULTICASTER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/cluster/NoOpConnectionOutputHandler.h b/RC9/qpid/cpp/src/qpid/cluster/NoOpConnectionOutputHandler.h
new file mode 100644
index 0000000000..74a376a657
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/NoOpConnectionOutputHandler.h
@@ -0,0 +1,47 @@
+#ifndef QPID_CLUSTER_NOOPCONNECTIONOUTPUTHANDLER_H
+#define QPID_CLUSTER_NOOPCONNECTIONOUTPUTHANDLER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <qpid/sys/ConnectionOutputHandler.h>
+
+namespace qpid {
+
+namespace framing { class AMQFrame; }
+
+namespace cluster {
+
+/**
+ * Output handler for frames sent to noop connections.
+ * Simply discards frames.
+ */
+class NoOpConnectionOutputHandler : public sys::ConnectionOutputHandler
+{
+ public:
+ virtual void send(framing::AMQFrame&) {}
+ virtual void close() {}
+ virtual void activateOutput() {}
+ virtual void giveReadCredit(int32_t) {}
+};
+
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_NOOPCONNECTIONOUTPUTHANDLER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/cluster/OutputInterceptor.cpp b/RC9/qpid/cpp/src/qpid/cluster/OutputInterceptor.cpp
new file mode 100644
index 0000000000..075023caea
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/OutputInterceptor.cpp
@@ -0,0 +1,121 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "OutputInterceptor.h"
+#include "Connection.h"
+#include "Cluster.h"
+#include "qpid/framing/ClusterConnectionDeliverDoOutputBody.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/log/Statement.h"
+#include <boost/current_function.hpp>
+
+
+namespace qpid {
+namespace cluster {
+
+using namespace framing;
+
+OutputInterceptor::OutputInterceptor(
+ cluster::Connection& p, sys::ConnectionOutputHandler& h)
+ : parent(p), next(&h), sent(), writeEstimate(p.getCluster().getWriteEstimate()),
+ moreOutput(), doingOutput()
+{}
+
+void OutputInterceptor::send(framing::AMQFrame& f) {
+ parent.getCluster().checkQuorum();
+ next->send(f);
+ if (!parent.isCatchUp())
+ sent += f.encodedSize();
+}
+
+void OutputInterceptor::activateOutput() {
+ if (parent.isCatchUp())
+ next->activateOutput();
+ else {
+ QPID_LOG(trace, parent << " activateOutput - sending doOutput");
+ moreOutput = true;
+ sendDoOutput();
+ }
+}
+
+void OutputInterceptor::giveReadCredit(int32_t credit) { next->giveReadCredit(credit); }
+
+// Called in write thread when the IO layer has no more data to write.
+// We do nothing in the write thread, we run doOutput only on delivery
+// of doOutput requests.
+bool OutputInterceptor::doOutput() {
+ QPID_LOG(trace, parent << " write idle.");
+ return false;
+}
+
+// Delivery of doOutput allows us to run the real connection doOutput()
+// which tranfers frames to the codec for writing.
+//
+void OutputInterceptor::deliverDoOutput(size_t requested) {
+ size_t buf = next->getBuffered();
+ if (parent.isLocal())
+ writeEstimate.delivered(requested, sent, buf); // Update the estimate.
+
+ // Run the real doOutput() till we have added the requested data or there's nothing to output.
+ sent = 0;
+ do {
+ moreOutput = parent.getBrokerConnection().doOutput();
+ } while (sent < requested && moreOutput);
+ sent += buf; // Include buffered data in the sent total.
+
+ QPID_LOG(trace, "Delivered doOutput: requested=" << requested << " output=" << sent << " more=" << moreOutput);
+
+ if (parent.isLocal() && moreOutput) {
+ QPID_LOG(trace, parent << " deliverDoOutput - sending doOutput, more output available.");
+ sendDoOutput();
+ }
+ else
+ doingOutput = false;
+}
+
+// Send a doOutput request if one is not already in flight.
+void OutputInterceptor::sendDoOutput() {
+ if (!parent.isLocal()) return;
+
+ doingOutput = true;
+ size_t request = writeEstimate.sending(getBuffered());
+
+ // Note we may send 0 size request if there's more than 2*estimate in the buffer.
+ // Send it anyway to keep the doOutput chain going until we are sure there's no more output
+ // (in deliverDoOutput)
+ //
+ parent.getCluster().getMulticast().mcastControl(
+ ClusterConnectionDeliverDoOutputBody(ProtocolVersion(), request), parent.getId());
+ QPID_LOG(trace, parent << "Send doOutput request for " << request);
+}
+
+void OutputInterceptor::setOutputHandler(sys::ConnectionOutputHandler& h) {
+ next = &h;
+}
+
+void OutputInterceptor::close() {
+ next->close();
+}
+
+size_t OutputInterceptor::getBuffered() const {
+ return next->getBuffered();
+}
+
+}} // namespace qpid::cluster
diff --git a/RC9/qpid/cpp/src/qpid/cluster/OutputInterceptor.h b/RC9/qpid/cpp/src/qpid/cluster/OutputInterceptor.h
new file mode 100644
index 0000000000..0ac15e747a
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/OutputInterceptor.h
@@ -0,0 +1,75 @@
+#ifndef QPID_CLUSTER_OUTPUTINTERCEPTOR_H
+#define QPID_CLUSTER_OUTPUTINTERCEPTOR_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "WriteEstimate.h"
+#include "qpid/sys/ConnectionOutputHandler.h"
+#include "qpid/broker/ConnectionFactory.h"
+#include <boost/function.hpp>
+
+namespace qpid {
+namespace framing { class AMQFrame; }
+namespace cluster {
+
+class Connection;
+
+/**
+ * Interceptor for connection OutputHandler, manages outgoing message replication.
+ */
+class OutputInterceptor : public sys::ConnectionOutputHandler {
+ public:
+ OutputInterceptor(cluster::Connection& p, sys::ConnectionOutputHandler& h);
+
+ // sys::ConnectionOutputHandler functions
+ void send(framing::AMQFrame& f);
+ void activateOutput();
+ void giveReadCredit(int32_t);
+ void close();
+ size_t getBuffered() const;
+
+ // Delivery point for doOutput requests.
+ void deliverDoOutput(size_t requested);
+ // Intercept doOutput requests on Connection.
+ bool doOutput();
+
+ void setOutputHandler(sys::ConnectionOutputHandler& h);
+
+ cluster::Connection& parent;
+
+ private:
+ typedef sys::Mutex::ScopedLock Locker;
+
+ void sendDoOutput();
+
+ mutable sys::Mutex lock;
+ sys::ConnectionOutputHandler* next;
+ size_t sent;
+ size_t lastDoOutput;
+ WriteEstimate writeEstimate;
+ bool moreOutput;
+ bool doingOutput;
+};
+
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_OUTPUTINTERCEPTOR_H*/
diff --git a/RC9/qpid/cpp/src/qpid/cluster/ProxyInputHandler.h b/RC9/qpid/cpp/src/qpid/cluster/ProxyInputHandler.h
new file mode 100644
index 0000000000..228f8d092d
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/ProxyInputHandler.h
@@ -0,0 +1,57 @@
+#ifndef QPID_CLUSTER_PROXYINPUTHANDLER_H
+#define QPID_CLUSTER_PROXYINPUTHANDLER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/ConnectionInputHandler.h"
+#include <boost/intrusive_ptr.hpp>
+
+namespace qpid {
+
+namespace framing { class AMQFrame; }
+
+namespace cluster {
+
+/**
+ * Proxies ConnectionInputHandler functions and ensures target.closed()
+ * is called, on deletion if not before.
+ */
+class ProxyInputHandler : public sys::ConnectionInputHandler
+{
+ public:
+ ProxyInputHandler(boost::intrusive_ptr<cluster::Connection> t) : target(t) {}
+ ~ProxyInputHandler() { closed(); }
+
+ void received(framing::AMQFrame& f) { target->received(f); }
+ void closed() { if (target) target->closed(); target = 0; }
+ void idleOut() { target->idleOut(); }
+ void idleIn() { target->idleIn(); }
+ bool doOutput() { return target->doOutput(); }
+ bool hasOutput() { return target->hasOutput(); }
+
+ private:
+ boost::intrusive_ptr<cluster::Connection> target;
+};
+
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_PROXYINPUTHANDLER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/cluster/Quorum.h b/RC9/qpid/cpp/src/qpid/cluster/Quorum.h
new file mode 100644
index 0000000000..f07b58dfa6
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/Quorum.h
@@ -0,0 +1,32 @@
+#ifndef QPID_CLUSTER_QUORUM_H
+#define QPID_CLUSTER_QUORUM_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "config.h"
+
+#if HAVE_LIBCMAN
+#include "Quorum_cman.h"
+#else
+#include "Quorum_null.h"
+#endif
+
+#endif /*!QPID_CLUSTER_QUORUM_H*/
diff --git a/RC9/qpid/cpp/src/qpid/cluster/Quorum_cman.cpp b/RC9/qpid/cpp/src/qpid/cluster/Quorum_cman.cpp
new file mode 100644
index 0000000000..d5df758b40
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/Quorum_cman.cpp
@@ -0,0 +1,49 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "Quorum_cman.h"
+#include "qpid/log/Statement.h"
+#include "qpid/Options.h"
+#include "qpid/sys/Time.h"
+
+namespace qpid {
+namespace cluster {
+
+Quorum::Quorum() : enable(false), cman(0) {}
+
+Quorum::~Quorum() { if (cman) cman_finish(cman); }
+
+void Quorum::init() {
+ QPID_LOG(info, "Waiting for cluster quorum");
+ enable = true;
+ cman = cman_init(0);
+ if (cman == 0) throw ErrnoException("Can't connect to cman service");
+ // FIXME aconway 2008-11-13: configure max wait.
+ for (int retry = 0; !cman_is_quorate(cman) && retry < 30; retry++) {
+ QPID_LOG(info, "Waiting for cluster quorum: " << sys::strError(errno));
+ sys::sleep(1);
+ }
+ if (!cman_is_quorate(cman))
+ throw ErrnoException("Timed out waiting for cluster quorum.");
+}
+
+bool Quorum::isQuorate() { return enable ? cman_is_quorate(cman) : true; }
+
+}} // namespace qpid::cluster
diff --git a/RC9/qpid/cpp/src/qpid/cluster/Quorum_cman.h b/RC9/qpid/cpp/src/qpid/cluster/Quorum_cman.h
new file mode 100644
index 0000000000..d0f8b2c954
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/Quorum_cman.h
@@ -0,0 +1,50 @@
+#ifndef QPID_CLUSTER_QUORUM_CMAN_H
+#define QPID_CLUSTER_QUORUM_CMAN_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+extern "C" {
+#include <libcman.h>
+}
+
+namespace qpid {
+
+class Options;
+
+namespace cluster {
+
+class Quorum {
+ public:
+ Quorum();
+ ~Quorum();
+ void init();
+ bool isQuorate();
+
+ private:
+ bool enable;
+ cman_handle_t cman;
+};
+
+
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_QUORUM_CMAN_H*/
diff --git a/RC9/qpid/cpp/src/qpid/cluster/Quorum_null.h b/RC9/qpid/cpp/src/qpid/cluster/Quorum_null.h
new file mode 100644
index 0000000000..cbb6c20708
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/Quorum_null.h
@@ -0,0 +1,37 @@
+#ifndef QPID_CLUSTER_QUORUM_NULL_H
+#define QPID_CLUSTER_QUORUM_NULL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+namespace qpid {
+namespace cluster {
+
+/** Null implementation of quorum. */
+
+class Quorum {
+ public:
+ void init() {}
+ bool isQuorate() { return true; }
+};
+
+#endif /*!QPID_CLUSTER_QUORUM_NULL_H*/
+
+}} // namespace qpid::cluster
diff --git a/RC9/qpid/cpp/src/qpid/cluster/WriteEstimate.cpp b/RC9/qpid/cpp/src/qpid/cluster/WriteEstimate.cpp
new file mode 100644
index 0000000000..4d840947f3
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/WriteEstimate.cpp
@@ -0,0 +1,64 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "WriteEstimate.h"
+#include "qpid/log/Statement.h"
+#include <boost/current_function.hpp>
+
+namespace qpid {
+namespace cluster {
+
+WriteEstimate::WriteEstimate(size_t initial)
+ : growing(true), estimate(initial), lastEstimate(initial) {}
+
+size_t WriteEstimate::sending(size_t buffered) {
+ // We want to send a doOutput request for enough data such
+ // that if estimate bytes are written before it is self
+ // delivered then what is left in the buffer plus the doOutput
+ // request will be estimate bytes.
+
+ size_t predictLeft = (buffered > estimate) ? buffered - estimate : 0;
+ size_t request = (estimate > predictLeft) ? estimate - predictLeft : 0;
+ return request;
+}
+
+size_t pad(size_t value) { return value + value/2; }
+
+void WriteEstimate::delivered(size_t last, size_t sent, size_t buffered) {
+ lastEstimate = last;
+ size_t wrote = sent > buffered ? sent - buffered : 0;
+ if (wrote == 0) // No change
+ return;
+ if (buffered > 0) { // Buffer was over-stocked, we wrote to capacity.
+ growing = false;
+ estimate = pad(wrote); // Estimate at 1.5 write for padding.
+ }
+ else if (wrote > estimate) { // Wrote everything, buffer was under-stocked
+ if (growing)
+ estimate = std::max(estimate*2, pad(wrote)); // Grow quickly if we have not yet seen an over-stock.
+ else
+ estimate = pad(wrote);
+ }
+}
+
+}} // namespace qpid::cluster
+
+
diff --git a/RC9/qpid/cpp/src/qpid/cluster/WriteEstimate.h b/RC9/qpid/cpp/src/qpid/cluster/WriteEstimate.h
new file mode 100644
index 0000000000..97b1435fcc
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/WriteEstimate.h
@@ -0,0 +1,69 @@
+#ifndef QPID_CLUSTER_WRITEESTIMATE_H
+#define QPID_CLUSTER_WRITEESTIMATE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Mutex.h"
+
+namespace qpid {
+namespace cluster {
+
+/**
+ * Estimate the amount of data that a connection can write between sending
+ * a doOutput notice and re-receiving it.
+ *
+ * The goal is to avoid ever write-idling the connection by sending
+ * the next doOutput request as soon as we've processed the previous
+ * one, such that data generated by the previous request will keep the
+ * writer busy till the next one is delivered.
+ *
+ */
+class WriteEstimate
+{
+ public:
+ WriteEstimate(size_t initial=4096);
+
+ /** About to send a doOutput request.
+ * Update estimation state and return size for next request.
+ */
+ size_t sending(size_t buffered);
+
+ /**
+ * doOutput request just delivered, not yet executed. Update the estimate.
+ * and estimate how much data to request in the next onOutput
+ * request. 0 means don't send an onOutput request.
+ *
+ * @param delivered value in doOutput control.
+ */
+ void delivered(size_t delivered, size_t sent, size_t buffered);
+
+ /** Last estimate delivered, i.e. known to cluster */
+ size_t getLastEstimate() const { return estimate; }
+
+ private:
+ bool growing;
+ size_t estimate, lastEstimate;
+};
+
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_WRITEESTIMATE_H*/
diff --git a/RC9/qpid/cpp/src/qpid/cluster/management-schema.xml b/RC9/qpid/cpp/src/qpid/cluster/management-schema.xml
new file mode 100644
index 0000000000..da19387cc6
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/management-schema.xml
@@ -0,0 +1,57 @@
+<schema package="org.apache.qpid.cluster">
+
+ <!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ -->
+
+ <!-- Type information:
+
+Numeric types with "_wm" suffix are watermarked numbers. These are compound
+values containing a current value, and a low and high water mark for the reporting
+interval. The low and high water marks are set to the current value at the
+beginning of each interval and track the minimum and maximum values of the statistic
+over the interval respectively.
+
+Access rights for configuration elements:
+
+RO => Read Only
+RC => Read/Create, can be set at create time only, read-only thereafter
+RW => Read/Write
+
+If access rights are omitted for a property, they are assumed to be RO.
+
+ -->
+
+ <class name="Cluster">
+ <property name="brokerRef" type="objId" references="Broker" access="RC" index="y" parentRef="y"/>
+ <property name="clusterName" type="sstr" access="RC" desc="Name of cluster this server is a member of"/>
+ <property name="clusterID" type="sstr" access="RO" desc="Globally uniquie ID (UUID) for this cluster instance"/>
+ <property name="publishedURL" type="sstr" access="RC" desc="URL this node advertizes itself as"/>
+ <property name="clusterSize" type="uint16" access="RO" desc="Number of brokers currently in the cluster"/>
+ <property name="status" type="sstr" access="RO" desc="Cluster node status (STALLED,ACTIVE,JOINING)"/>
+ <property name="members" type="lstr" access="RO" desc="List of member URLs delimited by ';'"/>
+
+ <method name="stopClusterNode"/>
+ <method name="stopFullCluster"/>
+
+ </class>
+
+
+
+</schema>
+
diff --git a/RC9/qpid/cpp/src/qpid/cluster/types.h b/RC9/qpid/cpp/src/qpid/cluster/types.h
new file mode 100644
index 0000000000..857b19cc8a
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/cluster/types.h
@@ -0,0 +1,84 @@
+#ifndef QPID_CLUSTER_TYPES_H
+#define QPID_CLUSTER_TYPES_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+
+#include "ClusterLeaveException.h"
+#include "config.h"
+#include "qpid/Url.h"
+
+#include <utility>
+#include <iosfwd>
+#include <string>
+
+#include <stdint.h>
+
+extern "C" {
+#ifdef HAVE_OPENAIS_CPG_H
+#include <openais/cpg.h>
+#elif HAVE_COROSYNC_CPG_H
+# include <corosync/cpg.h>
+#else
+# error "No cpg.h header file available"
+#endif
+}
+
+namespace qpid {
+namespace cluster {
+
+class Connection;
+
+/** Types of cluster event. */
+enum EventType { DATA, CONTROL };
+
+/** first=node-id, second=pid */
+struct MemberId : std::pair<uint32_t, uint32_t> {
+ explicit MemberId(uint64_t n) : std::pair<uint32_t,uint32_t>( n >> 32, n & 0xffffffff) {}
+ explicit MemberId(uint32_t node=0, uint32_t pid=0) : std::pair<uint32_t,uint32_t>(node, pid) {}
+ MemberId(const cpg_address& caddr) : std::pair<uint32_t,uint32_t>(caddr.nodeid, caddr.pid) {}
+ MemberId(const std::string&); // Decode from string.
+ uint32_t getNode() const { return first; }
+ uint32_t getPid() const { return second; }
+ operator uint64_t() const { return (uint64_t(first)<<32ull) + second; }
+
+ // AsMethodBody as string, network byte order.
+ std::string str() const;
+};
+
+inline bool operator==(const cpg_address& caddr, const MemberId& id) { return id == MemberId(caddr); }
+
+std::ostream& operator<<(std::ostream&, const MemberId&);
+
+struct ConnectionId : public std::pair<MemberId, Connection*> {
+ ConnectionId(const MemberId& m=MemberId(), Connection* c=0) : std::pair<MemberId, Connection*> (m,c) {}
+ ConnectionId(uint64_t m, uint64_t c)
+ : std::pair<MemberId, Connection*>(MemberId(m), reinterpret_cast<Connection*>(c)) {}
+ MemberId getMember() const { return first; }
+ Connection* getPointer() const { return second; }
+};
+
+std::ostream& operator<<(std::ostream&, const ConnectionId&);
+
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_TYPES_H*/
diff --git a/RC9/qpid/cpp/src/qpid/console/Agent.cpp b/RC9/qpid/cpp/src/qpid/console/Agent.cpp
new file mode 100644
index 0000000000..8b5a8adbb4
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/console/Agent.cpp
@@ -0,0 +1,30 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Agent.h"
+
+std::ostream& qpid::console::operator<<(std::ostream& o, const Agent& agent)
+{
+ o << "Agent at bank " << agent.getBrokerBank() << "." << agent.getAgentBank() <<
+ " (" << agent.getLabel() << ")";
+ return o;
+}
+
diff --git a/RC9/qpid/cpp/src/qpid/console/Agent.h b/RC9/qpid/cpp/src/qpid/console/Agent.h
new file mode 100644
index 0000000000..3307a1b44b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/console/Agent.h
@@ -0,0 +1,57 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _QPID_CONSOLE_AGENT_H_
+#define _QPID_CONSOLE_AGENT_H_
+
+#include "Broker.h"
+
+namespace qpid {
+namespace console {
+
+ /**
+ *
+ * \ingroup qmfconsoleapi
+ */
+ class Agent {
+ public:
+ typedef std::vector<Agent*> Vector;
+
+ Agent(Broker* _broker, uint32_t _bank, const std::string& _label) :
+ broker(_broker), brokerBank(broker->getBrokerBank()),
+ agentBank(_bank), label(_label) {}
+ Broker* getBroker() const { return broker; }
+ uint32_t getBrokerBank() const { return brokerBank; }
+ uint32_t getAgentBank() const { return agentBank; }
+ const std::string& getLabel() const { return label; }
+
+ private:
+ Broker* broker;
+ const uint32_t brokerBank;
+ const uint32_t agentBank;
+ const std::string label;
+ };
+
+ std::ostream& operator<<(std::ostream& o, const Agent& agent);
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/console/Broker.cpp b/RC9/qpid/cpp/src/qpid/console/Broker.cpp
new file mode 100644
index 0000000000..c6b1be1d31
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/console/Broker.cpp
@@ -0,0 +1,300 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Broker.h"
+#include "Object.h"
+#include "Value.h"
+#include "SessionManager.h"
+#include "ConsoleListener.h"
+#include "qpid/log/Statement.h"
+#include "qpid/sys/SystemInfo.h"
+
+using namespace qpid::client;
+using namespace qpid::console;
+using namespace qpid::framing;
+using namespace qpid::sys;
+using namespace std;
+
+Broker::Broker(SessionManager& sm, ConnectionSettings& settings) :
+ sessionManager(sm), connected(false), connectionSettings(settings),
+ reqsOutstanding(1), syncInFlight(false), topicBound(false), methodObject(0),
+ connThreadBody(*this), connThread(connThreadBody)
+{
+ string osName;
+ string nodeName;
+ string release;
+ string version;
+ string machine;
+
+ sys::SystemInfo::getSystemId(osName, nodeName, release, version, machine);
+ uint32_t pid = sys::SystemInfo::getParentProcessId();
+
+ stringstream text;
+
+ text << "qmfc-cpp-" << nodeName << "-" << pid;
+ amqpSessionId = string(text.str());
+
+ QPID_LOG(debug, "Broker::Broker: constructed, amqpSessionId=" << amqpSessionId);
+}
+
+Broker::~Broker()
+{
+}
+
+string Broker::getUrl() const
+{
+ stringstream url;
+ url << connectionSettings.host << ":" << connectionSettings.port;
+ return url.str();
+}
+
+void Broker::encodeHeader(framing::Buffer& buf, uint8_t opcode, uint32_t seq) const
+{
+ buf.putOctet('A');
+ buf.putOctet('M');
+ buf.putOctet('2');
+ buf.putOctet(opcode);
+ buf.putLong (seq);
+}
+
+bool Broker::checkHeader(framing::Buffer& buf, uint8_t *opcode, uint32_t *seq) const
+{
+ if (buf.getSize() < 8)
+ return false;
+
+ uint8_t h1 = buf.getOctet();
+ uint8_t h2 = buf.getOctet();
+ uint8_t h3 = buf.getOctet();
+
+ *opcode = buf.getOctet();
+ *seq = buf.getLong();
+
+ return h1 == 'A' && h2 == 'M' && h3 == '2';
+}
+
+void Broker::received(client::Message& msg)
+{
+ string data = msg.getData();
+ Buffer inBuffer(const_cast<char*>(data.c_str()), data.size());
+ uint8_t opcode;
+ uint32_t sequence;
+
+ if (checkHeader(inBuffer, &opcode, &sequence)) {
+ QPID_LOG(trace, "Broker::received: opcode=" << opcode << " seq=" << sequence);
+
+ if (opcode == 'b') sessionManager.handleBrokerResp(this, inBuffer, sequence);
+ else if (opcode == 'p') sessionManager.handlePackageInd(this, inBuffer, sequence);
+ else if (opcode == 'z') sessionManager.handleCommandComplete(this, inBuffer, sequence);
+ else if (opcode == 'q') sessionManager.handleClassInd(this, inBuffer, sequence);
+ else if (opcode == 'm') sessionManager.handleMethodResp(this, inBuffer, sequence);
+ else if (opcode == 'h') sessionManager.handleHeartbeatInd(this, inBuffer, sequence);
+ else if (opcode == 'e') sessionManager.handleEventInd(this, inBuffer, sequence);
+ else if (opcode == 's') sessionManager.handleSchemaResp(this, inBuffer, sequence);
+ else if (opcode == 'c') sessionManager.handleContentInd(this, inBuffer, sequence, true, false);
+ else if (opcode == 'i') sessionManager.handleContentInd(this, inBuffer, sequence, false, true);
+ else if (opcode == 'g') sessionManager.handleContentInd(this, inBuffer, sequence, true, true);
+ }
+}
+
+void Broker::resetAgents()
+{
+ for (AgentMap::iterator iter = agents.begin(); iter != agents.end(); iter++) {
+ if (sessionManager.listener != 0)
+ sessionManager.listener->delAgent(*(iter->second));
+ delete iter->second;
+ }
+
+ agents.clear();
+ agents[0x0000000100000000LL] = new Agent(this, 0, "BrokerAgent");
+}
+
+void Broker::updateAgent(const Object& object)
+{
+ uint32_t brokerBank = object.attrUint("brokerBank");
+ uint32_t agentBank = object.attrUint("agentBank");
+ uint64_t agentKey = ((uint64_t) brokerBank << 32) | (uint64_t) agentBank;
+ AgentMap::iterator iter = agents.find(agentKey);
+
+ if (object.isDeleted()) {
+ if (iter != agents.end()) {
+ if (sessionManager.listener != 0)
+ sessionManager.listener->delAgent(*(iter->second));
+ delete iter->second;
+ agents.erase(iter);
+ }
+ } else {
+ if (iter == agents.end()) {
+ Agent* agent = new Agent(this, agentBank, object.attrString("label"));
+ agents[agentKey] = agent;
+ if (sessionManager.listener != 0)
+ sessionManager.listener->newAgent(*agent);
+ }
+ }
+}
+
+void Broker::ConnectionThread::run()
+{
+ static const int delayMin(1);
+ static const int delayMax(128);
+ static const int delayFactor(2);
+ int delay(delayMin);
+ string dest("qmfc");
+
+ sessionId.generate();
+ queueName << "qmfc-" << sessionId;
+
+ while (true) {
+ try {
+ broker.topicBound = false;
+ broker.reqsOutstanding = 1;
+ connection.open(broker.connectionSettings);
+ session = connection.newSession(queueName.str());
+ subscriptions = new client::SubscriptionManager(session);
+
+ session.queueDeclare(arg::queue=queueName.str(), arg::autoDelete=true,
+ arg::exclusive=true);
+ session.exchangeBind(arg::exchange="amq.direct", arg::queue=queueName.str(),
+ arg::bindingKey=queueName.str());
+
+ subscriptions->setAcceptMode(ACCEPT_MODE_NONE);
+ subscriptions->setAcquireMode(ACQUIRE_MODE_PRE_ACQUIRED);
+ subscriptions->subscribe(broker, queueName.str(), dest);
+ subscriptions->setFlowControl(dest, FlowControl::unlimited());
+ {
+ Mutex::ScopedLock _lock(connLock);
+ operational = true;
+ broker.resetAgents();
+ broker.connected = true;
+ broker.sessionManager.handleBrokerConnect(&broker);
+ broker.sessionManager.startProtocol(&broker);
+ try {
+ Mutex::ScopedUnlock _unlock(connLock);
+ subscriptions->run();
+ } catch (std::exception) {}
+
+ operational = false;
+ broker.connected = false;
+ broker.sessionManager.handleBrokerDisconnect(&broker);
+ }
+ delay = delayMin;
+ delete subscriptions;
+ subscriptions = 0;
+ session.close();
+ } catch (std::exception &e) {
+ QPID_LOG(debug, " outer exception: " << e.what());
+ if (delay < delayMax)
+ delay *= delayFactor;
+ }
+
+ ::sleep(delay);
+ }
+}
+
+Broker::ConnectionThread::~ConnectionThread()
+{
+ if (subscriptions != 0) {
+ delete subscriptions;
+ }
+}
+
+void Broker::ConnectionThread::sendBuffer(Buffer& buf, uint32_t length,
+ const string& exchange, const string& routingKey)
+{
+ {
+ Mutex::ScopedLock _lock(connLock);
+ if (!operational)
+ return;
+ }
+
+ client::Message msg;
+ string data;
+
+ buf.getRawData(data, length);
+ msg.getDeliveryProperties().setRoutingKey(routingKey);
+ msg.getMessageProperties().setReplyTo(ReplyTo("amq.direct", queueName.str()));
+ msg.setData(data);
+ try {
+ session.messageTransfer(arg::content=msg, arg::destination=exchange);
+ } catch(std::exception&) {}
+}
+
+void Broker::ConnectionThread::bindExchange(const std::string& exchange, const std::string& key)
+{
+ {
+ Mutex::ScopedLock _lock(connLock);
+ if (!operational)
+ return;
+ }
+
+ QPID_LOG(debug, "Broker::ConnectionThread::bindExchange: exchange=" << exchange << " key=" << key);
+ session.exchangeBind(arg::exchange=exchange, arg::queue=queueName.str(),
+ arg::bindingKey=key);
+}
+
+void Broker::waitForStable()
+{
+ Mutex::ScopedLock l(lock);
+ if (reqsOutstanding == 0)
+ return;
+ syncInFlight = true;
+ while (reqsOutstanding != 0) {
+ bool result = cond.wait(lock, AbsTime(now(), TIME_SEC * sessionManager.settings.getTimeout));
+ if (!result)
+ throw(Exception("Timed out waiting for broker to synchronize"));
+ }
+}
+
+void Broker::incOutstanding()
+{
+ Mutex::ScopedLock l(lock);
+ reqsOutstanding++;
+}
+
+void Broker::decOutstanding()
+{
+ Mutex::ScopedLock l(lock);
+ reqsOutstanding--;
+ if (reqsOutstanding == 0) {
+ if (!topicBound) {
+ topicBound = true;
+ for (vector<string>::const_iterator iter = sessionManager.bindingKeyList.begin();
+ iter != sessionManager.bindingKeyList.end(); iter++)
+ connThreadBody.bindExchange("qpid.management", *iter);
+ }
+ if (syncInFlight) {
+ syncInFlight = false;
+ cond.notify();
+ }
+ }
+}
+
+void Broker::appendAgents(Agent::Vector& agentlist) const
+{
+ for (AgentMap::const_iterator iter = agents.begin(); iter != agents.end(); iter++) {
+ agentlist.push_back(iter->second);
+ }
+}
+
+ostream& qpid::console::operator<<(ostream& o, const Broker& k)
+{
+ o << "Broker: " << k.connectionSettings.host << ":" << k.connectionSettings.port;
+ return o;
+}
diff --git a/RC9/qpid/cpp/src/qpid/console/Broker.h b/RC9/qpid/cpp/src/qpid/console/Broker.h
new file mode 100644
index 0000000000..9df2380dff
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/console/Broker.h
@@ -0,0 +1,130 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _QPID_CONSOLE_BROKER_H_
+#define _QPID_CONSOLE_BROKER_H_
+
+#include "qpid/client/Connection.h"
+#include "qpid/client/ConnectionSettings.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/Session.h"
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/MessageListener.h"
+#include "qpid/sys/Thread.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Condition.h"
+#include "qpid/Url.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/framing/Uuid.h"
+#include <string>
+#include <iostream>
+
+namespace qpid {
+namespace console {
+ class SessionManager;
+ class Agent;
+ class Object;
+
+ /**
+ *
+ * \ingroup qpidconsoleapi
+ */
+ class Broker : public client::MessageListener {
+ public:
+ Broker(SessionManager& sm, client::ConnectionSettings& settings);
+ ~Broker();
+
+ bool isConnected() const { return connected; }
+ const std::string& getError() const { return error; }
+ const std::string& getSessionId() const { return amqpSessionId; }
+ const framing::Uuid& getBrokerId() const { return brokerId; }
+ uint32_t getBrokerBank() const { return 1; }
+ void addBinding(const std::string& key) {
+ connThreadBody.bindExchange("qpid.management", key);
+ }
+ std::string getUrl() const;
+
+ private:
+ friend class SessionManager;
+ friend class Object;
+ typedef std::map<uint64_t,Agent*> AgentMap;
+ static const int SYNC_TIME = 60;
+
+ SessionManager& sessionManager;
+ AgentMap agents;
+ client::SubscriptionManager* subscription;
+ bool connected;
+ std::string error;
+ std::string amqpSessionId;
+ client::ConnectionSettings connectionSettings;
+ sys::Mutex lock;
+ sys::Condition cond;
+ framing::Uuid brokerId;
+ uint32_t reqsOutstanding;
+ bool syncInFlight;
+ bool topicBound;
+ Object* methodObject;
+
+ friend class ConnectionThread;
+ class ConnectionThread : public sys::Runnable {
+ bool operational;
+ Broker& broker;
+ framing::Uuid sessionId;
+ client::Connection connection;
+ client::Session session;
+ client::SubscriptionManager* subscriptions;
+ std::stringstream queueName;
+ sys::Mutex connLock;
+ void run();
+ public:
+ ConnectionThread(Broker& _broker) :
+ operational(false), broker(_broker), subscriptions(0) {}
+ ~ConnectionThread();
+ void sendBuffer(qpid::framing::Buffer& buf,
+ uint32_t length,
+ const std::string& exchange = "qpid.management",
+ const std::string& routingKey = "broker");
+ void bindExchange(const std::string& exchange, const std::string& key);
+ };
+
+ ConnectionThread connThreadBody;
+ sys::Thread connThread;
+
+ void encodeHeader(framing::Buffer& buf, uint8_t opcode, uint32_t seq = 0) const;
+ bool checkHeader(framing::Buffer& buf, uint8_t *opcode, uint32_t *seq) const;
+ void received(client::Message& msg);
+ void resetAgents();
+ void updateAgent(const Object& object);
+ void waitForStable();
+ void incOutstanding();
+ void decOutstanding();
+ void setBrokerId(const framing::Uuid& id) { brokerId = id; }
+ void appendAgents(std::vector<Agent*>& agents) const;
+
+ friend std::ostream& operator<<(std::ostream& o, const Broker& k);
+ };
+
+ std::ostream& operator<<(std::ostream& o, const Broker& k);
+}
+}
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/console/ClassKey.cpp b/RC9/qpid/cpp/src/qpid/console/ClassKey.cpp
new file mode 100644
index 0000000000..6aa2bcb117
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/console/ClassKey.cpp
@@ -0,0 +1,104 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "ClassKey.h"
+#include <string.h>
+
+using namespace std;
+using namespace qpid::console;
+
+ClassKey::ClassKey(const string& _package, const string& _name, const uint8_t* _hash) :
+ package(_package), name(_name)
+{
+ ::memcpy(hash, _hash, HASH_SIZE);
+}
+
+string ClassKey::getHashString() const
+{
+ char cstr[36];
+ ::sprintf(cstr, "%02x%02x%02x%02x-%02x%02x%02x%02x-%02x%02x%02x%02x-%02x%02x%02x%02x",
+ hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7],
+ hash[8], hash[9], hash[10], hash[11], hash[12], hash[13], hash[14], hash[15]);
+ return string(cstr);
+}
+
+string ClassKey::str() const
+{
+ string result(package + ":" + name + "(" + getHashString() + ")");
+ return result;
+}
+
+bool ClassKey::operator==(const ClassKey& other) const
+{
+ return ::memcmp(hash, other.hash, HASH_SIZE) == 0 &&
+ name == other.name &&
+ package == other.package;
+}
+
+bool ClassKey::operator!=(const ClassKey& other) const
+{
+ return !(*this == other);
+}
+
+bool ClassKey::operator<(const ClassKey& other) const
+{
+ int cmp = ::memcmp(hash, other.hash, HASH_SIZE);
+ if (cmp != 0)
+ return cmp < 0;
+ cmp = name.compare(other.name);
+ if (cmp != 0)
+ return cmp < 0;
+ return package < other.package;
+}
+
+bool ClassKey::operator>(const ClassKey& other) const
+{
+ int cmp = ::memcmp(hash, other.hash, HASH_SIZE);
+ if (cmp != 0)
+ return cmp > 0;
+ cmp = name.compare(other.name);
+ if (cmp != 0)
+ return cmp > 0;
+ return package > other.package;
+}
+
+bool ClassKey::operator<=(const ClassKey& other) const
+{
+ return !(*this > other);
+}
+
+bool ClassKey::operator>=(const ClassKey& other) const
+{
+ return !(*this < other);
+}
+
+void ClassKey::encode(framing::Buffer& buffer) const
+{
+ buffer.putShortString(package);
+ buffer.putShortString(name);
+ buffer.putBin128(const_cast<uint8_t*>(hash));
+}
+
+ostream& qpid::console::operator<<(ostream& o, const ClassKey& k)
+{
+ o << k.str();
+ return o;
+}
diff --git a/RC9/qpid/cpp/src/qpid/console/ClassKey.h b/RC9/qpid/cpp/src/qpid/console/ClassKey.h
new file mode 100644
index 0000000000..f6617e22d5
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/console/ClassKey.h
@@ -0,0 +1,65 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _QPID_CONSOLE_CLASSKEY_H_
+#define _QPID_CONSOLE_CLASSKEY_H_
+
+#include <string>
+#include "Package.h"
+#include "qpid/framing/Buffer.h"
+
+namespace qpid {
+namespace console {
+
+ /**
+ *
+ * \ingroup qmfconsoleapi
+ */
+ class ClassKey {
+ public:
+ static const int HASH_SIZE = 16;
+
+ ClassKey(const std::string& package, const std::string& name, const uint8_t* hash);
+
+ const std::string& getPackageName() const { return package; }
+ const std::string& getClassName() const { return name; }
+ const uint8_t* getHash() const { return hash; }
+ std::string getHashString() const;
+ std::string str() const;
+ bool operator==(const ClassKey& other) const;
+ bool operator!=(const ClassKey& other) const;
+ bool operator<(const ClassKey& other) const;
+ bool operator>(const ClassKey& other) const;
+ bool operator<=(const ClassKey& other) const;
+ bool operator>=(const ClassKey& other) const;
+ void encode(framing::Buffer& buffer) const;
+
+ private:
+ std::string package;
+ std::string name;
+ uint8_t hash[HASH_SIZE];
+ };
+
+ std::ostream& operator<<(std::ostream& o, const ClassKey& k);
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/console/ConsoleListener.h b/RC9/qpid/cpp/src/qpid/console/ConsoleListener.h
new file mode 100644
index 0000000000..d0db6034f6
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/console/ConsoleListener.h
@@ -0,0 +1,96 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _QPID_CONSOLE_CONSOLE_LISTENER_H_
+#define _QPID_CONSOLE_CONSOLE_LISTENER_H_
+
+#include <string>
+#include "Broker.h"
+#include "ClassKey.h"
+#include "Object.h"
+#include "Event.h"
+
+namespace qpid {
+namespace console {
+
+ /**
+ * Implement a subclass of ConsoleListener and subscribe it using
+ * the SessionManager to receive indications.
+ *
+ * \ingroup qmfconsoleapi
+ */
+ class ConsoleListener{
+ public:
+ virtual ~ConsoleListener() {};
+
+ /** Invoked when a connection is established to a broker
+ */
+ virtual void brokerConnected(const Broker&) {}
+
+ /** Invoked when the connection to a broker is lost
+ */
+ virtual void brokerDisconnected(const Broker&) {}
+
+ /** Invoked when a QMF package is discovered.
+ */
+ virtual void newPackage(const std::string&) {}
+
+ /** Invoked when a new class is discovered. Session.getSchema can be
+ * used to obtain details about the class.
+ */
+ virtual void newClass(const ClassKey&) {}
+
+ /** Invoked when a QMF agent is discovered.
+ */
+ virtual void newAgent(const Agent&) {}
+
+ /** Invoked when a QMF agent disconects.
+ */
+ virtual void delAgent(const Agent&) {}
+
+ /** Invoked when an object is updated.
+ */
+ virtual void objectProps(Broker&, Object&) {}
+
+ /** Invoked when an object is updated.
+ */
+ virtual void objectStats(Broker&, Object&) {}
+
+ /** Invoked when an event is raised.
+ */
+ virtual void event(Event&) {}
+
+ /**
+ */
+ //virtual void heartbeat(Agent&, uint64_t) {}
+
+ /**
+ */
+ virtual void brokerInfo(Broker&) {}
+
+ /**
+ */
+ //virtual void methodResponse(Broker&, uint32_t seq, MethodResponse&) {}
+ };
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/console/Event.cpp b/RC9/qpid/cpp/src/qpid/console/Event.cpp
new file mode 100644
index 0000000000..51f043159c
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/console/Event.cpp
@@ -0,0 +1,205 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Broker.h"
+#include "ClassKey.h"
+#include "Schema.h"
+#include "Event.h"
+#include "Value.h"
+#include "qpid/sys/Time.h"
+#include "qpid/framing/Buffer.h"
+
+using namespace qpid::console;
+using namespace std;
+using qpid::framing::Uuid;
+using qpid::framing::FieldTable;
+
+Event::Event(Broker* _broker, SchemaClass* _schema, framing::Buffer& buffer) :
+ broker(_broker), schema(_schema)
+{
+ timestamp = buffer.getLongLong();
+ severity = (Severity) buffer.getOctet();
+ for (vector<SchemaArgument*>::const_iterator aIter = schema->arguments.begin();
+ aIter != schema->arguments.end(); aIter++) {
+ SchemaArgument* argument = *aIter;
+ attributes[argument->name] = argument->decodeValue(buffer);
+ }
+}
+
+const ClassKey& Event::getClassKey() const
+{
+ return schema->getClassKey();
+}
+
+string Event::getSeverityString() const
+{
+ switch (severity) {
+ case EMERGENCY : return string("EMER");
+ case ALERT : return string("ALERT");
+ case CRITICAL : return string("CRIT");
+ case ERROR : return string("ERROR");
+ case WARNING : return string("WARN");
+ case NOTICE : return string("NOTIC");
+ case INFO : return string("INFO");
+ case DEBUG : return string("DEBUG");
+ }
+ return string("<UNKNOWN>");
+}
+
+ObjectId Event::attrRef(const string& key) const
+{
+ Object::AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return ObjectId();
+ Value::Ptr val = iter->second;
+ if (!val->isObjectId())
+ return ObjectId();
+ return val->asObjectId();
+}
+
+uint32_t Event::attrUint(const string& key) const
+{
+ Object::AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return 0;
+ Value::Ptr val = iter->second;
+ if (!val->isUint())
+ return 0;
+ return val->asUint();
+}
+
+int32_t Event::attrInt(const string& key) const
+{
+ Object::AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return 0;
+ Value::Ptr val = iter->second;
+ if (!val->isInt())
+ return 0;
+ return val->asInt();
+}
+
+uint64_t Event::attrUint64(const string& key) const
+{
+ Object::AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return 0;
+ Value::Ptr val = iter->second;
+ if (!val->isUint64())
+ return 0;
+ return val->asUint64();
+}
+
+int64_t Event::attrInt64(const string& key) const
+{
+ Object::AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return 0;
+ Value::Ptr val = iter->second;
+ if (!val->isInt64())
+ return 0;
+ return val->asInt64();
+}
+
+string Event::attrString(const string& key) const
+{
+ Object::AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return string();
+ Value::Ptr val = iter->second;
+ if (!val->isString())
+ return string();
+ return val->asString();
+}
+
+bool Event::attrBool(const string& key) const
+{
+ Object::AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return false;
+ Value::Ptr val = iter->second;
+ if (!val->isBool())
+ return false;
+ return val->asBool();
+}
+
+float Event::attrFloat(const string& key) const
+{
+ Object::AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return 0.0;
+ Value::Ptr val = iter->second;
+ if (!val->isFloat())
+ return 0.0;
+ return val->asFloat();
+}
+
+double Event::attrDouble(const string& key) const
+{
+ Object::AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return 0.0;
+ Value::Ptr val = iter->second;
+ if (!val->isDouble())
+ return 0.0;
+ return val->asDouble();
+}
+
+Uuid Event::attrUuid(const string& key) const
+{
+ Object::AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return Uuid();
+ Value::Ptr val = iter->second;
+ if (!val->isUuid())
+ return Uuid();
+ return val->asUuid();
+}
+
+FieldTable Event::attrMap(const string& key) const
+{
+ Object::AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return FieldTable();
+ Value::Ptr val = iter->second;
+ if (!val->isMap())
+ return FieldTable();
+ return val->asMap();
+}
+
+
+std::ostream& qpid::console::operator<<(std::ostream& o, const Event& event)
+{
+ const ClassKey& key = event.getClassKey();
+ sys::AbsTime aTime(sys::AbsTime(), sys::Duration(event.getTimestamp()));
+ o << aTime << " " << event.getSeverityString() << " " <<
+ key.getPackageName() << ":" << key.getClassName() <<
+ " broker=" << event.getBroker()->getUrl();
+
+ const Object::AttributeMap& attributes = event.getAttributes();
+ for (Object::AttributeMap::const_iterator iter = attributes.begin();
+ iter != attributes.end(); iter++) {
+ o << " " << iter->first << "=" << iter->second->str();
+ }
+ return o;
+}
+
+
diff --git a/RC9/qpid/cpp/src/qpid/console/Event.h b/RC9/qpid/cpp/src/qpid/console/Event.h
new file mode 100644
index 0000000000..c212b72889
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/console/Event.h
@@ -0,0 +1,83 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _QPID_CONSOLE_EVENT_H_
+#define _QPID_CONSOLE_EVENT_H_
+
+#include "Object.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/framing/FieldTable.h"
+
+namespace qpid {
+namespace framing {
+ class Buffer;
+}
+namespace console {
+
+ class Broker;
+ class SchemaClass;
+ class ClassKey;
+
+ /**
+ *
+ * \ingroup qmfconsoleapi
+ */
+ class Event {
+ public:
+ typedef enum {
+ EMERGENCY = 0, ALERT = 1, CRITICAL = 2, ERROR = 3, WARNING = 4,
+ NOTICE = 5, INFO = 6, DEBUG = 7
+ } Severity;
+
+ Event(Broker* broker, SchemaClass* schemaClass, framing::Buffer& buffer);
+ Broker* getBroker() const { return broker; }
+ const ClassKey& getClassKey() const;
+ SchemaClass* getSchema() const { return schema; }
+ const Object::AttributeMap& getAttributes() const { return attributes; }
+ uint64_t getTimestamp() const { return timestamp; }
+ uint8_t getSeverity() const { return severity; }
+ std::string getSeverityString() const;
+
+ ObjectId attrRef(const std::string& key) const;
+ uint32_t attrUint(const std::string& key) const;
+ int32_t attrInt(const std::string& key) const;
+ uint64_t attrUint64(const std::string& key) const;
+ int64_t attrInt64(const std::string& key) const;
+ std::string attrString(const std::string& key) const;
+ bool attrBool(const std::string& key) const;
+ float attrFloat(const std::string& key) const;
+ double attrDouble(const std::string& key) const;
+ framing::Uuid attrUuid(const std::string& key) const;
+ framing::FieldTable attrMap(const std::string& key) const;
+
+ private:
+ Broker* broker;
+ SchemaClass* schema;
+ uint64_t timestamp;
+ Severity severity;
+ Object::AttributeMap attributes;
+ };
+
+ std::ostream& operator<<(std::ostream& o, const Event& event);
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/console/Object.cpp b/RC9/qpid/cpp/src/qpid/console/Object.cpp
new file mode 100644
index 0000000000..da8ab962e0
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/console/Object.cpp
@@ -0,0 +1,383 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "SessionManager.h"
+#include "Broker.h"
+#include "Object.h"
+#include "Schema.h"
+#include "ClassKey.h"
+#include "Value.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/sys/Mutex.h"
+
+using namespace qpid::console;
+using namespace qpid::sys;
+using namespace std;
+using qpid::framing::Uuid;
+using qpid::framing::FieldTable;
+
+void Object::AttributeMap::addRef(const string& key, const ObjectId& val)
+{
+ (*this)[key] = Value::Ptr(new RefValue(val));
+}
+
+void Object::AttributeMap::addUint(const string& key, uint32_t val)
+{
+ (*this)[key] = Value::Ptr(new UintValue(val));
+}
+
+void Object::AttributeMap::addInt(const string& key, int32_t val)
+{
+ (*this)[key] = Value::Ptr(new IntValue(val));
+}
+
+void Object::AttributeMap::addUint64(const string& key, uint64_t val)
+{
+ (*this)[key] = Value::Ptr(new Uint64Value(val));
+}
+
+void Object::AttributeMap::addInt64(const string& key, int64_t val)
+{
+ (*this)[key] = Value::Ptr(new Int64Value(val));
+}
+
+void Object::AttributeMap::addString(const string& key, const string& val)
+{
+ (*this)[key] = Value::Ptr(new StringValue(val));
+}
+
+void Object::AttributeMap::addBool(const string& key, bool val)
+{
+ (*this)[key] = Value::Ptr(new BoolValue(val));
+}
+
+void Object::AttributeMap::addFloat(const string& key, float val)
+{
+ (*this)[key] = Value::Ptr(new FloatValue(val));
+}
+
+void Object::AttributeMap::addDouble(const string& key, double val)
+{
+ (*this)[key] = Value::Ptr(new DoubleValue(val));
+}
+
+void Object::AttributeMap::addUuid(const string& key, const framing::Uuid& val)
+{
+ (*this)[key] = Value::Ptr(new UuidValue(val));
+}
+
+void Object::AttributeMap::addMap(const string& key, const framing::FieldTable& val)
+{
+ (*this)[key] = Value::Ptr(new MapValue(val));
+}
+
+Object::Object(Broker* b, SchemaClass* s, framing::Buffer& buffer, bool prop, bool stat) :
+ broker(b), schema(s), pendingMethod(0)
+{
+ currentTime = buffer.getLongLong();
+ createTime = buffer.getLongLong();
+ deleteTime = buffer.getLongLong();
+ objectId.decode(buffer);
+
+ if (prop) {
+ set<string> excludes;
+ parsePresenceMasks(buffer, excludes);
+ for (vector<SchemaProperty*>::const_iterator pIter = schema->properties.begin();
+ pIter != schema->properties.end(); pIter++) {
+ SchemaProperty* property = *pIter;
+ if (excludes.count(property->name) != 0) {
+ attributes[property->name] = Value::Ptr(new NullValue());
+ } else {
+ attributes[property->name] = property->decodeValue(buffer);
+ }
+ }
+ }
+
+ if (stat) {
+ for (vector<SchemaStatistic*>::const_iterator sIter = schema->statistics.begin();
+ sIter != schema->statistics.end(); sIter++) {
+ SchemaStatistic* statistic = *sIter;
+ attributes[statistic->name] = statistic->decodeValue(buffer);
+ }
+ }
+}
+
+Object::~Object() {}
+
+const ClassKey& Object::getClassKey() const
+{
+ return schema->getClassKey();
+}
+
+string Object::getIndex() const
+{
+ string result;
+
+ for (vector<SchemaProperty*>::const_iterator pIter = schema->properties.begin();
+ pIter != schema->properties.end(); pIter++) {
+ SchemaProperty* property = *pIter;
+ if (property->isIndex) {
+ AttributeMap::const_iterator vIter = attributes.find(property->name);
+ if (vIter != attributes.end()) {
+ if (!result.empty())
+ result += ":";
+ result += vIter->second->str();
+ }
+ }
+ }
+ return result;
+}
+
+void Object::mergeUpdate(const Object& /*updated*/)
+{
+ // TODO
+}
+
+void Object::invokeMethod(const string name, const AttributeMap& args, MethodResponse& result)
+{
+ for (vector<SchemaMethod*>::const_iterator iter = schema->methods.begin();
+ iter != schema->methods.end(); iter++) {
+ if ((*iter)->name == name) {
+ SchemaMethod* method = *iter;
+ char rawbuffer[65536];
+ framing::Buffer buffer(rawbuffer, 65536);
+ uint32_t sequence = broker->sessionManager.sequenceManager.reserve("method");
+ pendingMethod = method;
+ broker->methodObject = this;
+ broker->encodeHeader(buffer, 'M', sequence);
+ objectId.encode(buffer);
+ schema->key.encode(buffer);
+ buffer.putShortString(name);
+
+ for (vector<SchemaArgument*>::const_iterator aIter = method->arguments.begin();
+ aIter != method->arguments.end(); aIter++) {
+ SchemaArgument* arg = *aIter;
+ if (arg->dirInput) {
+ AttributeMap::const_iterator attr = args.find(arg->name);
+ if (attr != args.end()) {
+ ValueFactory::encodeValue(arg->typeCode, attr->second, buffer);
+ } else {
+ // TODO Use the default value instead of throwing
+ throw Exception("Missing arguments in method call");
+ }
+ }
+ }
+
+ uint32_t length = buffer.getPosition();
+ buffer.reset();
+ stringstream routingKey;
+ routingKey << "agent." << objectId.getBrokerBank() << "." << objectId.getAgentBank();
+ broker->connThreadBody.sendBuffer(buffer, length, "qpid.management", routingKey.str());
+
+ {
+ Mutex::ScopedLock l(broker->lock);
+ bool ok = true;
+ while (pendingMethod != 0 && ok) {
+ ok = broker->cond.wait(broker->lock, AbsTime(now(), broker->sessionManager.settings.methodTimeout * TIME_SEC));
+ }
+
+ if (!ok) {
+ result.code = 0x1001;
+ result.text.assign("Method call timed out");
+ result.arguments.clear();
+ } else {
+ result = methodResponse;
+ }
+ }
+ }
+ }
+}
+
+void Object::handleMethodResp(framing::Buffer& buffer, uint32_t sequence)
+{
+ broker->sessionManager.sequenceManager.release(sequence);
+ methodResponse.code = buffer.getLong();
+ buffer.getMediumString(methodResponse.text);
+ methodResponse.arguments.clear();
+
+ for (vector<SchemaArgument*>::const_iterator aIter = pendingMethod->arguments.begin();
+ aIter != pendingMethod->arguments.end(); aIter++) {
+ SchemaArgument* arg = *aIter;
+ if (arg->dirOutput) {
+ methodResponse.arguments[arg->name] = arg->decodeValue(buffer);
+ }
+ }
+
+ {
+ Mutex::ScopedLock l(broker->lock);
+ pendingMethod = 0;
+ broker->cond.notify();
+ }
+}
+
+ObjectId Object::attrRef(const string& key) const
+{
+ AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return ObjectId();
+ Value::Ptr val = iter->second;
+ if (!val->isObjectId())
+ return ObjectId();
+ return val->asObjectId();
+}
+
+uint32_t Object::attrUint(const string& key) const
+{
+ AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return 0;
+ Value::Ptr val = iter->second;
+ if (!val->isUint())
+ return 0;
+ return val->asUint();
+}
+
+int32_t Object::attrInt(const string& key) const
+{
+ AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return 0;
+ Value::Ptr val = iter->second;
+ if (!val->isInt())
+ return 0;
+ return val->asInt();
+}
+
+uint64_t Object::attrUint64(const string& key) const
+{
+ AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return 0;
+ Value::Ptr val = iter->second;
+ if (!val->isUint64())
+ return 0;
+ return val->asUint64();
+}
+
+int64_t Object::attrInt64(const string& key) const
+{
+ AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return 0;
+ Value::Ptr val = iter->second;
+ if (!val->isInt64())
+ return 0;
+ return val->asInt64();
+}
+
+string Object::attrString(const string& key) const
+{
+ AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return string();
+ Value::Ptr val = iter->second;
+ if (!val->isString())
+ return string();
+ return val->asString();
+}
+
+bool Object::attrBool(const string& key) const
+{
+ AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return false;
+ Value::Ptr val = iter->second;
+ if (!val->isBool())
+ return false;
+ return val->asBool();
+}
+
+float Object::attrFloat(const string& key) const
+{
+ AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return 0.0;
+ Value::Ptr val = iter->second;
+ if (!val->isFloat())
+ return 0.0;
+ return val->asFloat();
+}
+
+double Object::attrDouble(const string& key) const
+{
+ AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return 0.0;
+ Value::Ptr val = iter->second;
+ if (!val->isDouble())
+ return 0.0;
+ return val->asDouble();
+}
+
+Uuid Object::attrUuid(const string& key) const
+{
+ AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return Uuid();
+ Value::Ptr val = iter->second;
+ if (!val->isUuid())
+ return Uuid();
+ return val->asUuid();
+}
+
+FieldTable Object::attrMap(const string& key) const
+{
+ AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return FieldTable();
+ Value::Ptr val = iter->second;
+ if (!val->isMap())
+ return FieldTable();
+ return val->asMap();
+}
+
+void Object::parsePresenceMasks(framing::Buffer& buffer, set<string>& excludeList)
+{
+ excludeList.clear();
+ uint8_t bit = 0;
+ uint8_t mask = 0;
+
+ for (vector<SchemaProperty*>::const_iterator pIter = schema->properties.begin();
+ pIter != schema->properties.end(); pIter++) {
+ SchemaProperty* property = *pIter;
+ if (property->isOptional) {
+ if (bit == 0) {
+ mask = buffer.getOctet();
+ bit = 1;
+ }
+ if ((mask & bit) == 0)
+ excludeList.insert(property->name);
+ if (bit == 0x80)
+ bit = 0;
+ else
+ bit = bit << 1;
+ }
+ }
+}
+
+ostream& qpid::console::operator<<(ostream& o, const Object& object)
+{
+ const ClassKey& key = object.getClassKey();
+ o << key.getPackageName() << ":" << key.getClassName() << "[" << object.getObjectId() << "] " <<
+ object.getIndex();
+ return o;
+}
+
diff --git a/RC9/qpid/cpp/src/qpid/console/Object.h b/RC9/qpid/cpp/src/qpid/console/Object.h
new file mode 100644
index 0000000000..54a3e0f6e8
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/console/Object.h
@@ -0,0 +1,119 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _QPID_CONSOLE_OBJECT_H_
+#define _QPID_CONSOLE_OBJECT_H_
+
+#include "ObjectId.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/framing/FieldTable.h"
+#include <boost/shared_ptr.hpp>
+#include <map>
+#include <set>
+#include <vector>
+
+namespace qpid {
+namespace framing {
+ class Buffer;
+}
+namespace console {
+
+ class Broker;
+ class SchemaClass;
+ class SchemaMethod;
+ class ObjectId;
+ class ClassKey;
+ class Value;
+
+ /**
+ * \ingroup qmfconsoleapi
+ */
+ struct MethodResponse {
+ uint32_t code;
+ std::string text;
+ std::map<std::string, boost::shared_ptr<Value> > arguments;
+ };
+
+ class Object {
+ public:
+ typedef std::vector<Object> Vector;
+ struct AttributeMap : public std::map<std::string, boost::shared_ptr<Value> > {
+ void addRef(const std::string& key, const ObjectId& val);
+ void addUint(const std::string& key, uint32_t val);
+ void addInt(const std::string& key, int32_t val);
+ void addUint64(const std::string& key, uint64_t val);
+ void addInt64(const std::string& key, int64_t val);
+ void addString(const std::string& key, const std::string& val);
+ void addBool(const std::string& key, bool val);
+ void addFloat(const std::string& key, float val);
+ void addDouble(const std::string& key, double val);
+ void addUuid(const std::string& key, const framing::Uuid& val);
+ void addMap(const std::string& key, const framing::FieldTable& val);
+ };
+
+ Object(Broker* broker, SchemaClass* schemaClass, framing::Buffer& buffer, bool prop, bool stat);
+ ~Object();
+
+ Broker* getBroker() const { return broker; }
+ const ObjectId& getObjectId() const { return objectId; }
+ const ClassKey& getClassKey() const;
+ SchemaClass* getSchema() const { return schema; }
+ uint64_t getCurrentTime() const { return currentTime; }
+ uint64_t getCreateTime() const { return createTime; }
+ uint64_t getDeleteTime() const { return deleteTime; }
+ bool isDeleted() const { return deleteTime != 0; }
+ std::string getIndex() const;
+ void mergeUpdate(const Object& updated);
+ const AttributeMap& getAttributes() const { return attributes; }
+ void invokeMethod(const std::string name, const AttributeMap& args, MethodResponse& result);
+ void handleMethodResp(framing::Buffer& buffer, uint32_t sequence);
+
+ ObjectId attrRef(const std::string& key) const;
+ uint32_t attrUint(const std::string& key) const;
+ int32_t attrInt(const std::string& key) const;
+ uint64_t attrUint64(const std::string& key) const;
+ int64_t attrInt64(const std::string& key) const;
+ std::string attrString(const std::string& key) const;
+ bool attrBool(const std::string& key) const;
+ float attrFloat(const std::string& key) const;
+ double attrDouble(const std::string& key) const;
+ framing::Uuid attrUuid(const std::string& key) const;
+ framing::FieldTable attrMap(const std::string& key) const;
+
+ private:
+ Broker* broker;
+ SchemaClass* schema;
+ ObjectId objectId;
+ uint64_t currentTime;
+ uint64_t createTime;
+ uint64_t deleteTime;
+ AttributeMap attributes;
+ SchemaMethod* pendingMethod;
+ MethodResponse methodResponse;
+
+ void parsePresenceMasks(framing::Buffer& buffer, std::set<std::string>& excludeList);
+ };
+
+ std::ostream& operator<<(std::ostream& o, const Object& object);
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/console/ObjectId.cpp b/RC9/qpid/cpp/src/qpid/console/ObjectId.cpp
new file mode 100644
index 0000000000..535e59e88d
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/console/ObjectId.cpp
@@ -0,0 +1,52 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "ObjectId.h"
+#include "qpid/framing/Buffer.h"
+
+using namespace qpid::console;
+using namespace std;
+
+ObjectId::ObjectId(framing::Buffer& buffer)
+{
+ decode(buffer);
+}
+
+void ObjectId::decode(framing::Buffer& buffer)
+{
+ first = buffer.getLongLong();
+ second = buffer.getLongLong();
+}
+
+void ObjectId::encode(framing::Buffer& buffer)
+{
+ buffer.putLongLong(first);
+ buffer.putLongLong(second);
+}
+
+ostream& qpid::console::operator<<(ostream& o, const ObjectId& id)
+{
+ o << (int) id.getFlags() << "-" << id.getSequence() << "-" << id.getBrokerBank() << "-" <<
+ id.getAgentBank() << "-" << id.getObject();
+ return o;
+}
+
+
diff --git a/RC9/qpid/cpp/src/qpid/console/ObjectId.h b/RC9/qpid/cpp/src/qpid/console/ObjectId.h
new file mode 100644
index 0000000000..c9c2fc852a
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/console/ObjectId.h
@@ -0,0 +1,60 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _QPID_CONSOLE_OBJECTID_H
+#define _QPID_CONSOLE_OBJECTID_H
+
+#include <iostream>
+
+namespace qpid {
+namespace framing {
+ class Buffer;
+}
+namespace console {
+
+ /**
+ *
+ * \ingroup qmfconsoleapi
+ */
+ class ObjectId {
+ public:
+ ObjectId() : first(0), second(0) {}
+ ObjectId(framing::Buffer& buffer);
+
+ uint8_t getFlags() const { return (first & 0xF000000000000000LL) >> 60; }
+ uint16_t getSequence() const { return (first & 0x0FFF000000000000LL) >> 48; }
+ uint32_t getBrokerBank() const { return (first & 0x0000FFFFF0000000LL) >> 28; }
+ uint32_t getAgentBank() const { return first & 0x000000000FFFFFFFLL; }
+ uint64_t getObject() const { return second; }
+ bool isDurable() const { return getSequence() == 0; }
+ void decode(framing::Buffer& buffer);
+ void encode(framing::Buffer& buffer);
+ void setValue(uint64_t f, uint64_t s) { first = f; second = s; }
+
+ private:
+ uint64_t first;
+ uint64_t second;
+ };
+
+ std::ostream& operator<<(std::ostream& o, const ObjectId& id);
+}
+}
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/console/Package.cpp b/RC9/qpid/cpp/src/qpid/console/Package.cpp
new file mode 100644
index 0000000000..81a04445f2
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/console/Package.cpp
@@ -0,0 +1,41 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Package.h"
+
+using namespace qpid::console;
+
+SchemaClass* Package::getClass(const std::string& className, uint8_t* hash)
+{
+ NameHash key(className, hash);
+ ClassMap::iterator iter = classes.find(key);
+ if (iter != classes.end())
+ return iter->second;
+ return 0;
+}
+
+void Package::addClass(const std::string& className, uint8_t* hash, SchemaClass* schemaClass)
+{
+ NameHash key(className, hash);
+ ClassMap::iterator iter = classes.find(key);
+ if (iter == classes.end())
+ classes[key] = schemaClass;
+}
diff --git a/RC9/qpid/cpp/src/qpid/console/Package.h b/RC9/qpid/cpp/src/qpid/console/Package.h
new file mode 100644
index 0000000000..a8679dff19
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/console/Package.h
@@ -0,0 +1,76 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _QPID_CONSOLE_PACKAGE_H_
+#define _QPID_CONSOLE_PACKAGE_H_
+
+#include <string>
+#include <map>
+
+namespace qpid {
+namespace console {
+ class SchemaClass;
+
+ /**
+ *
+ * \ingroup qmfconsoleapi
+ */
+ class Package {
+ public:
+ Package(const std::string& n) : name(n) {}
+ const std::string& getName() const { return name; }
+
+ private:
+ friend class SessionManager;
+ struct NameHash {
+ std::string name;
+ uint8_t hash[16];
+ NameHash(const std::string& n, const uint8_t* h) : name(n) {
+ for (int i = 0; i < 16; i++)
+ hash[i] = h[i];
+ }
+ };
+
+ struct NameHashComp {
+ bool operator() (const NameHash& lhs, const NameHash& rhs) const
+ {
+ if (lhs.name != rhs.name)
+ return lhs.name < rhs.name;
+ else
+ for (int i = 0; i < 16; i++)
+ if (lhs.hash[i] != rhs.hash[i])
+ return lhs.hash[i] < rhs.hash[i];
+ return false;
+ }
+ };
+
+ typedef std::map<NameHash, SchemaClass*, NameHashComp> ClassMap;
+
+ const std::string name;
+ ClassMap classes;
+
+ SchemaClass* getClass(const std::string& className, uint8_t* hash);
+ void addClass(const std::string& className, uint8_t* hash,
+ SchemaClass* schemaClass);
+ };
+}
+}
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/console/Schema.cpp b/RC9/qpid/cpp/src/qpid/console/Schema.cpp
new file mode 100644
index 0000000000..31d947cdd5
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/console/Schema.cpp
@@ -0,0 +1,155 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Schema.h"
+#include "Value.h"
+#include "qpid/framing/FieldTable.h"
+
+using namespace qpid::console;
+using std::string;
+using std::vector;
+
+SchemaArgument::SchemaArgument(framing::Buffer& buffer, bool forMethod)
+{
+ framing::FieldTable map;
+ map.decode(buffer);
+
+ name = map.getAsString("name");
+ typeCode = map.getAsInt("type");
+ unit = map.getAsString("unit");
+ min = map.getAsInt("min");
+ max = map.getAsInt("max");
+ maxLen = map.getAsInt("maxlen");
+ desc = map.getAsString("desc");
+
+ dirInput = false;
+ dirOutput = false;
+ if (forMethod) {
+ string dir(map.getAsString("dir"));
+ if (dir.find('I') != dir.npos || dir.find('i') != dir.npos)
+ dirInput = true;
+ if (dir.find('O') != dir.npos || dir.find('o') != dir.npos)
+ dirOutput = true;
+ }
+}
+
+Value::Ptr SchemaArgument::decodeValue(framing::Buffer& buffer)
+{
+ return ValueFactory::newValue(typeCode, buffer);
+}
+
+SchemaProperty::SchemaProperty(framing::Buffer& buffer)
+{
+ framing::FieldTable map;
+ map.decode(buffer);
+
+ name = map.getAsString("name");
+ typeCode = map.getAsInt("type");
+ accessCode = map.getAsInt("access");
+ isIndex = map.getAsInt("index") != 0;
+ isOptional = map.getAsInt("optional") != 0;
+ unit = map.getAsString("unit");
+ min = map.getAsInt("min");
+ max = map.getAsInt("max");
+ maxLen = map.getAsInt("maxlen");
+ desc = map.getAsString("desc");
+}
+
+Value::Ptr SchemaProperty::decodeValue(framing::Buffer& buffer)
+{
+ return ValueFactory::newValue(typeCode, buffer);
+}
+
+SchemaStatistic::SchemaStatistic(framing::Buffer& buffer)
+{
+ framing::FieldTable map;
+ map.decode(buffer);
+
+ name = map.getAsString("name");
+ typeCode = map.getAsInt("type");
+ unit = map.getAsString("unit");
+ desc = map.getAsString("desc");
+}
+
+Value::Ptr SchemaStatistic::decodeValue(framing::Buffer& buffer)
+{
+ return ValueFactory::newValue(typeCode, buffer);
+}
+
+SchemaMethod::SchemaMethod(framing::Buffer& buffer)
+{
+ framing::FieldTable map;
+ map.decode(buffer);
+
+ name = map.getAsString("name");
+ desc = map.getAsString("desc");
+ int argCount = map.getAsInt("argCount");
+
+ for (int i = 0; i < argCount; i++)
+ arguments.push_back(new SchemaArgument(buffer, true));
+}
+
+SchemaMethod::~SchemaMethod()
+{
+ for (vector<SchemaArgument*>::iterator iter = arguments.begin();
+ iter != arguments.end(); iter++)
+ delete *iter;
+}
+
+SchemaClass::SchemaClass(const uint8_t _kind, const ClassKey& _key, framing::Buffer& buffer) :
+ kind(_kind), key(_key)
+{
+ if (kind == KIND_TABLE) {
+ uint16_t propCount = buffer.getShort();
+ uint16_t statCount = buffer.getShort();
+ uint16_t methodCount = buffer.getShort();
+
+ for (uint16_t idx = 0; idx < propCount; idx++)
+ properties.push_back(new SchemaProperty(buffer));
+ for (uint16_t idx = 0; idx < statCount; idx++)
+ statistics.push_back(new SchemaStatistic(buffer));
+ for (uint16_t idx = 0; idx < methodCount; idx++)
+ methods.push_back(new SchemaMethod(buffer));
+
+ } else if (kind == KIND_EVENT) {
+ uint16_t argCount = buffer.getShort();
+
+ for (uint16_t idx = 0; idx < argCount; idx++)
+ arguments.push_back(new SchemaArgument(buffer));
+ }
+}
+
+SchemaClass::~SchemaClass()
+{
+ for (vector<SchemaProperty*>::iterator iter = properties.begin();
+ iter != properties.end(); iter++)
+ delete *iter;
+ for (vector<SchemaStatistic*>::iterator iter = statistics.begin();
+ iter != statistics.end(); iter++)
+ delete *iter;
+ for (vector<SchemaMethod*>::iterator iter = methods.begin();
+ iter != methods.end(); iter++)
+ delete *iter;
+ for (vector<SchemaArgument*>::iterator iter = arguments.begin();
+ iter != arguments.end(); iter++)
+ delete *iter;
+}
+
diff --git a/RC9/qpid/cpp/src/qpid/console/Schema.h b/RC9/qpid/cpp/src/qpid/console/Schema.h
new file mode 100644
index 0000000000..aacedfe23f
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/console/Schema.h
@@ -0,0 +1,105 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _QPID_CONSOLE_SCHEMA_H_
+#define _QPID_CONSOLE_SCHEMA_H_
+
+#include "ClassKey.h"
+#include <boost/shared_ptr.hpp>
+#include <vector>
+
+namespace qpid {
+namespace framing {
+ class Buffer;
+}
+namespace console {
+ class Value;
+
+ struct SchemaArgument {
+ SchemaArgument(framing::Buffer& buffer, bool forMethod = false);
+ boost::shared_ptr<Value> decodeValue(framing::Buffer& buffer);
+
+ std::string name;
+ uint8_t typeCode;
+ bool dirInput;
+ bool dirOutput;
+ std::string unit;
+ int min;
+ int max;
+ int maxLen;
+ std::string desc;
+ std::string defaultVal;
+ };
+
+ struct SchemaProperty {
+ SchemaProperty(framing::Buffer& buffer);
+ boost::shared_ptr<Value> decodeValue(framing::Buffer& buffer);
+
+ std::string name;
+ uint8_t typeCode;
+ uint8_t accessCode;
+ bool isIndex;
+ bool isOptional;
+ std::string unit;
+ int min;
+ int max;
+ int maxLen;
+ std::string desc;
+ };
+
+ struct SchemaStatistic {
+ SchemaStatistic(framing::Buffer& buffer);
+ boost::shared_ptr<Value> decodeValue(framing::Buffer& buffer);
+
+ std::string name;
+ uint8_t typeCode;
+ std::string unit;
+ std::string desc;
+ };
+
+ struct SchemaMethod {
+ SchemaMethod(framing::Buffer& buffer);
+ ~SchemaMethod();
+
+ std::string name;
+ std::string desc;
+ std::vector<SchemaArgument*> arguments;
+ };
+
+ struct SchemaClass {
+ static const uint8_t KIND_TABLE = 1;
+ static const uint8_t KIND_EVENT = 2;
+
+ SchemaClass(const uint8_t kind, const ClassKey& key, framing::Buffer& buffer);
+ ~SchemaClass();
+ const ClassKey& getClassKey() const { return key; }
+
+ const uint8_t kind;
+ const ClassKey key;
+ std::vector<SchemaProperty*> properties;
+ std::vector<SchemaStatistic*> statistics;
+ std::vector<SchemaMethod*> methods;
+ std::vector<SchemaArgument*> arguments;
+ };
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/console/SequenceManager.cpp b/RC9/qpid/cpp/src/qpid/console/SequenceManager.cpp
new file mode 100644
index 0000000000..ff777430c0
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/console/SequenceManager.cpp
@@ -0,0 +1,48 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "SequenceManager.h"
+
+using namespace qpid::console;
+using namespace qpid::sys;
+using std::string;
+using std::cout;
+using std::endl;
+
+uint32_t SequenceManager::reserve(const std::string& context)
+{
+ Mutex::ScopedLock l(lock);
+ uint32_t result = sequence++;
+ pending[result] = context;
+ return result;
+}
+
+std::string SequenceManager::release(uint32_t seq)
+{
+ Mutex::ScopedLock l(lock);
+ std::map<uint32_t, string>::iterator iter = pending.find(seq);
+ if (iter == pending.end())
+ return string();
+ string result(iter->second);
+ pending.erase(iter);
+ return result;
+}
+
diff --git a/RC9/qpid/cpp/src/qpid/console/SequenceManager.h b/RC9/qpid/cpp/src/qpid/console/SequenceManager.h
new file mode 100644
index 0000000000..c7a8c20fe6
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/console/SequenceManager.h
@@ -0,0 +1,53 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _QPID_CONSOLE_SEQUENCEMANAGER_H_
+#define _QPID_CONSOLE_SEQUENCEMANAGER_H_
+
+#include "qpid/sys/Mutex.h"
+#include <map>
+#include <string>
+#include <set>
+
+namespace qpid {
+namespace console {
+
+ /**
+ *
+ * \ingroup qpidconsoleapi
+ */
+ class SequenceManager {
+ public:
+ typedef std::set<uint32_t> set;
+
+ SequenceManager() : sequence(0) {}
+ uint32_t reserve(const std::string& context = "");
+ std::string release(uint32_t seq);
+
+ private:
+ sys::Mutex lock;
+ uint32_t sequence;
+ std::map<uint32_t, std::string> pending;
+ };
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/console/SessionManager.cpp b/RC9/qpid/cpp/src/qpid/console/SessionManager.cpp
new file mode 100644
index 0000000000..6aa347e051
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/console/SessionManager.cpp
@@ -0,0 +1,462 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "SessionManager.h"
+#include "Schema.h"
+#include "Agent.h"
+#include "qpid/console/ConsoleListener.h"
+#include "qpid/log/Statement.h"
+#include "qpid/sys/Time.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/framing/FieldTable.h"
+
+using namespace qpid::console;
+using namespace qpid::sys;
+using namespace std;
+using qpid::framing::Buffer;
+using qpid::framing::FieldTable;
+
+SessionManager::SessionManager(ConsoleListener* _listener, Settings _settings) :
+ listener(_listener), settings(_settings)
+{
+ bindingKeys();
+}
+
+Broker* SessionManager::addBroker(client::ConnectionSettings& settings)
+{
+ Broker* broker(new Broker(*this, settings));
+ {
+ Mutex::ScopedLock l(brokerListLock);
+ brokers.push_back(broker);
+ }
+ return broker;
+}
+
+void SessionManager::delBroker(Broker* broker)
+{
+ Mutex::ScopedLock l(brokerListLock);
+ for (vector<Broker*>::iterator iter = brokers.begin();
+ iter != brokers.end(); iter++)
+ if (*iter == broker) {
+ brokers.erase(iter);
+ return;
+ }
+}
+
+void SessionManager::getPackages(NameVector& packageNames)
+{
+ allBrokersStable();
+ packageNames.clear();
+ {
+ Mutex::ScopedLock l(lock);
+ for (map<string, Package*>::iterator iter = packages.begin();
+ iter != packages.end(); iter++)
+ packageNames.push_back(iter->first);
+ }
+}
+
+void SessionManager::getClasses(KeyVector& classKeys, const std::string& packageName)
+{
+ allBrokersStable();
+ classKeys.clear();
+ map<string, Package*>::iterator iter = packages.find(packageName);
+ if (iter == packages.end())
+ return;
+
+ Package& package = *(iter->second);
+ for (Package::ClassMap::const_iterator piter = package.classes.begin();
+ piter != package.classes.end(); piter++) {
+ ClassKey key(piter->second->getClassKey());
+ classKeys.push_back(key);
+ }
+}
+
+SchemaClass& SessionManager::getSchema(const ClassKey& classKey)
+{
+ allBrokersStable();
+ map<string, Package*>::iterator iter = packages.find(classKey.getPackageName());
+ if (iter == packages.end())
+ throw Exception("Unknown package");
+
+ Package& package = *(iter->second);
+ Package::NameHash key(classKey.getClassName(), classKey.getHash());
+ Package::ClassMap::iterator cIter = package.classes.find(key);
+ if (cIter == package.classes.end())
+ throw Exception("Unknown class");
+
+ return *(cIter->second);
+}
+
+void SessionManager::bindPackage(const std::string& packageName)
+{
+ stringstream key;
+ key << "console.obj.*.*." << packageName << ".#";
+ bindingKeyList.push_back(key.str());
+ for (vector<Broker*>::iterator iter = brokers.begin(); iter != brokers.end(); iter++)
+ (*iter)->addBinding(key.str());
+}
+
+void SessionManager::bindClass(const ClassKey& classKey)
+{
+ bindClass(classKey.getPackageName(), classKey.getClassName());
+}
+
+void SessionManager::bindClass(const std::string& packageName, const std::string& className)
+{
+ stringstream key;
+ key << "console.obj.*.*." << packageName << "." << className << ".#";
+ bindingKeyList.push_back(key.str());
+ for (vector<Broker*>::iterator iter = brokers.begin();
+ iter != brokers.end(); iter++)
+ (*iter)->addBinding(key.str());
+}
+
+void SessionManager::getAgents(Agent::Vector& agents, Broker* broker)
+{
+ agents.clear();
+ if (broker != 0) {
+ broker->appendAgents(agents);
+ } else {
+ for (vector<Broker*>::iterator iter = brokers.begin(); iter != brokers.end(); iter++) {
+ (*iter)->appendAgents(agents);
+ }
+ }
+}
+
+void SessionManager::getObjects(Object::Vector& objects, const std::string& className,
+ Broker* _broker, Agent* _agent)
+{
+ Agent::Vector agentList;
+
+ if (_agent != 0) {
+ agentList.push_back(_agent);
+ _agent->getBroker()->waitForStable();
+ } else {
+ if (_broker != 0) {
+ _broker->appendAgents(agentList);
+ _broker->waitForStable();
+ } else {
+ allBrokersStable();
+ Mutex::ScopedLock _lock(brokerListLock);
+ for (vector<Broker*>::iterator iter = brokers.begin(); iter != brokers.end(); iter++) {
+ (*iter)->appendAgents(agentList);
+ }
+ }
+ }
+
+ FieldTable ft;
+ uint32_t sequence;
+ ft.setString("_class", className);
+
+ getResult.clear();
+ syncSequenceList.clear();
+ error = string();
+
+ for (Agent::Vector::iterator iter = agentList.begin(); iter != agentList.end(); iter++) {
+ Agent* agent = *iter;
+ char rawbuffer[512];
+ Buffer buffer(rawbuffer, 512);
+ stringstream routingKey;
+ routingKey << "agent." << agent->getBrokerBank() << "." << agent->getAgentBank();
+ {
+ Mutex::ScopedLock _lock(lock);
+ sequence = sequenceManager.reserve("multiget");
+ syncSequenceList.insert(sequence);
+ }
+ agent->getBroker()->encodeHeader(buffer, 'G', sequence);
+ ft.encode(buffer);
+ uint32_t length = buffer.getPosition();
+ buffer.reset();
+ agent->getBroker()->connThreadBody.sendBuffer(buffer, length, "qpid.management", routingKey.str());
+ }
+
+ {
+ Mutex::ScopedLock _lock(lock);
+ while (!syncSequenceList.empty() && error.empty()) {
+ cv.wait(lock, AbsTime(now(), settings.getTimeout * TIME_SEC));
+ }
+ }
+
+ objects = getResult;
+}
+
+void SessionManager::bindingKeys()
+{
+ bindingKeyList.push_back("schema.#");
+ if (settings.rcvObjects && settings.rcvEvents && settings.rcvHeartbeats && !settings.userBindings) {
+ bindingKeyList.push_back("console.#");
+ } else {
+ if (settings.rcvObjects && !settings.userBindings)
+ bindingKeyList.push_back("console.obj.#");
+ else
+ bindingKeyList.push_back("console.obj.*.*.org.apache.qpid.broker.agent");
+ if (settings.rcvEvents)
+ bindingKeyList.push_back("console.event.#");
+ if (settings.rcvHeartbeats)
+ bindingKeyList.push_back("console.heartbeat");
+ }
+}
+
+void SessionManager::allBrokersStable()
+{
+ Mutex::ScopedLock l(brokerListLock);
+ for (vector<Broker*>::iterator iter = brokers.begin();
+ iter != brokers.end(); iter++)
+ (*iter)->waitForStable();
+}
+
+void SessionManager::startProtocol(Broker* broker)
+{
+ char rawbuffer[512];
+ Buffer buffer(rawbuffer, 512);
+
+ broker->encodeHeader(buffer, 'B');
+ uint32_t length = 512 - buffer.available();
+ buffer.reset();
+ broker->connThreadBody.sendBuffer(buffer, length);
+}
+
+
+void SessionManager::handleBrokerResp(Broker* broker, Buffer& inBuffer, uint32_t)
+{
+ framing::Uuid brokerId;
+
+ brokerId.decode(inBuffer);
+ broker->setBrokerId(brokerId);
+
+ char rawbuffer[512];
+ Buffer buffer(rawbuffer, 512);
+
+ uint32_t sequence = sequenceManager.reserve("startup");
+ broker->encodeHeader(buffer, 'P', sequence);
+ uint32_t length = 512 - buffer.available();
+ buffer.reset();
+ broker->connThreadBody.sendBuffer(buffer, length);
+
+ if (listener != 0) {
+ listener->brokerInfo(*broker);
+ }
+}
+
+void SessionManager::handlePackageInd(Broker* broker, Buffer& inBuffer, uint32_t)
+{
+ string packageName;
+ inBuffer.getShortString(packageName);
+
+ {
+ Mutex::ScopedLock l(lock);
+ map<string, Package*>::iterator iter = packages.find(packageName);
+ if (iter == packages.end()) {
+ packages[packageName] = new Package(packageName);
+ if (listener != 0)
+ listener->newPackage(packageName);
+ }
+ }
+
+ broker->incOutstanding();
+ char rawbuffer[512];
+ Buffer buffer(rawbuffer, 512);
+
+ uint32_t sequence = sequenceManager.reserve("startup");
+ broker->encodeHeader(buffer, 'Q', sequence);
+ buffer.putShortString(packageName);
+ uint32_t length = 512 - buffer.available();
+ buffer.reset();
+ broker->connThreadBody.sendBuffer(buffer, length);
+}
+
+void SessionManager::handleCommandComplete(Broker* broker, Buffer& inBuffer, uint32_t sequence)
+{
+ Mutex::ScopedLock l(lock);
+ uint32_t resultCode = inBuffer.getLong();
+ string resultText;
+ inBuffer.getShortString(resultText);
+ string context = sequenceManager.release(sequence);
+ if (resultCode != 0)
+ QPID_LOG(debug, "Received error in completion: " << resultCode << " " << resultText);
+ if (context == "startup") {
+ broker->decOutstanding();
+ } else if (context == "multiget") {
+ if (syncSequenceList.count(sequence) == 1) {
+ syncSequenceList.erase(sequence);
+ if (syncSequenceList.empty()) {
+ cv.notify();
+ }
+ }
+ }
+ // TODO: Other context cases
+}
+
+void SessionManager::handleClassInd(Broker* broker, Buffer& inBuffer, uint32_t)
+{
+ uint8_t kind;
+ string packageName;
+ string className;
+ uint8_t hash[16];
+
+ kind = inBuffer.getOctet();
+ inBuffer.getShortString(packageName);
+ inBuffer.getShortString(className);
+ inBuffer.getBin128(hash);
+
+ {
+ Mutex::ScopedLock l(lock);
+ map<string, Package*>::iterator pIter = packages.find(packageName);
+ if (pIter == packages.end() || pIter->second->getClass(className, hash))
+ return;
+ }
+
+ broker->incOutstanding();
+ char rawbuffer[512];
+ Buffer buffer(rawbuffer, 512);
+
+ uint32_t sequence = sequenceManager.reserve("startup");
+ broker->encodeHeader(buffer, 'S', sequence);
+ buffer.putShortString(packageName);
+ buffer.putShortString(className);
+ buffer.putBin128(hash);
+ uint32_t length = 512 - buffer.available();
+ buffer.reset();
+ broker->connThreadBody.sendBuffer(buffer, length);
+}
+
+void SessionManager::handleMethodResp(Broker* broker, Buffer& buffer, uint32_t sequence)
+{
+ if (broker->methodObject) {
+ broker->methodObject->handleMethodResp(buffer, sequence);
+ }
+}
+
+void SessionManager::handleHeartbeatInd(Broker* /*broker*/, Buffer& /*inBuffer*/, uint32_t /*sequence*/)
+{
+}
+
+void SessionManager::handleEventInd(Broker* broker, Buffer& buffer, uint32_t /*sequence*/)
+{
+ string packageName;
+ string className;
+ uint8_t hash[16];
+ SchemaClass* schemaClass;
+
+ buffer.getShortString(packageName);
+ buffer.getShortString(className);
+ buffer.getBin128(hash);
+
+ {
+ Mutex::ScopedLock l(lock);
+ map<string, Package*>::iterator pIter = packages.find(packageName);
+ if (pIter == packages.end())
+ return;
+ schemaClass = pIter->second->getClass(className, hash);
+ if (schemaClass == 0)
+ return;
+ }
+
+ Event event(broker, schemaClass, buffer);
+
+ if (listener)
+ listener->event(event);
+}
+
+void SessionManager::handleSchemaResp(Broker* broker, Buffer& inBuffer, uint32_t sequence)
+{
+ uint8_t kind;
+ string packageName;
+ string className;
+ uint8_t hash[16];
+
+ kind = inBuffer.getOctet();
+ inBuffer.getShortString(packageName);
+ inBuffer.getShortString(className);
+ inBuffer.getBin128(hash);
+
+ {
+ Mutex::ScopedLock l(lock);
+ map<string, Package*>::iterator pIter = packages.find(packageName);
+ if (pIter != packages.end() && !pIter->second->getClass(className, hash)) {
+ ClassKey key(packageName, className, hash);
+ SchemaClass* schemaClass(new SchemaClass(kind, key, inBuffer));
+ pIter->second->addClass(className, hash, schemaClass);
+ if (listener != 0) {
+ listener->newClass(schemaClass->getClassKey());
+ }
+ }
+ }
+
+ sequenceManager.release(sequence);
+ broker->decOutstanding();
+}
+
+void SessionManager::handleContentInd(Broker* broker, Buffer& buffer, uint32_t sequence, bool prop, bool stat)
+{
+ string packageName;
+ string className;
+ uint8_t hash[16];
+ SchemaClass* schemaClass;
+
+ buffer.getShortString(packageName);
+ buffer.getShortString(className);
+ buffer.getBin128(hash);
+
+ {
+ Mutex::ScopedLock l(lock);
+ map<string, Package*>::iterator pIter = packages.find(packageName);
+ if (pIter == packages.end())
+ return;
+ schemaClass = pIter->second->getClass(className, hash);
+ if (schemaClass == 0)
+ return;
+ }
+
+ Object object(broker, schemaClass, buffer, prop, stat);
+
+ if (prop && className == "agent" && packageName == "org.apache.qpid.broker")
+ broker->updateAgent(object);
+
+ {
+ Mutex::ScopedLock l(lock);
+ if (syncSequenceList.count(sequence) == 1) {
+ if (!object.isDeleted())
+ getResult.push_back(object);
+ }
+ return;
+ }
+
+ if (listener) {
+ if (prop)
+ listener->objectProps(*broker, object);
+ if (stat)
+ listener->objectStats(*broker, object);
+ }
+}
+
+void SessionManager::handleBrokerConnect(Broker* broker)
+{
+ if (listener != 0)
+ listener->brokerConnected(*broker);
+}
+
+void SessionManager::handleBrokerDisconnect(Broker* broker)
+{
+ if (listener != 0)
+ listener->brokerDisconnected(*broker);
+}
+
diff --git a/RC9/qpid/cpp/src/qpid/console/SessionManager.h b/RC9/qpid/cpp/src/qpid/console/SessionManager.h
new file mode 100644
index 0000000000..27df00494c
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/console/SessionManager.h
@@ -0,0 +1,199 @@
+#ifndef _QPID_CONSOLE_SESSION_MANAGER_H
+#define _QPID_CONSOLE_SESSION_MANAGER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Broker.h"
+#include "Package.h"
+#include "SequenceManager.h"
+#include "ClassKey.h"
+#include "Schema.h"
+#include "Agent.h"
+#include "Object.h"
+#include "ObjectId.h"
+#include "Value.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Condition.h"
+#include "qpid/client/ConnectionSettings.h"
+#include <string>
+#include <vector>
+
+namespace qpid {
+namespace console {
+
+class ConsoleListener;
+
+/**
+ *
+ * \ingroup qmfconsoleapi
+ */
+class SessionManager
+{
+ public:
+ typedef std::vector<std::string> NameVector;
+ typedef std::vector<ClassKey> KeyVector;
+ ~SessionManager() {}
+
+ struct Settings {
+ bool rcvObjects;
+ bool rcvEvents;
+ bool rcvHeartbeats;
+ bool userBindings;
+ uint32_t methodTimeout;
+ uint32_t getTimeout;
+
+ Settings() : rcvObjects(true), rcvEvents(true), rcvHeartbeats(true), userBindings(false),
+ methodTimeout(20), getTimeout(20)
+ {}
+ };
+
+ /** Create a new SessionManager
+ *
+ * Provide your own subclass of ConsoleListener to receive updates and indications
+ * asynchronously or leave it as its default and use only synchronous methods.
+ *
+ *@param listener Listener object to receive asynchronous indications.
+ *@param rcvObjects Listener wishes to receive managed object data.
+ *@param rcvEvents Listener wishes to receive events.
+ *@param rcvHeartbeats Listener wishes to receive agent heartbeats.
+ *@param userBindings If rcvObjects is true, userBindings allows the console client
+ * to control which object classes are received. See the bindPackage and bindClass
+ * methods. If userBindings is false, the listener will receive updates for all
+ * object classes.
+ */
+ SessionManager(ConsoleListener* listener = 0,
+ Settings settings = Settings());
+
+ /** Connect a broker to the console session
+ *
+ *@param settings Connection settings for client access
+ *@return broker object if operation is successful
+ * an exception shall be thrown.
+ */
+ Broker* addBroker(client::ConnectionSettings& settings);
+
+ /** Disconnect a broker from the console session
+ *
+ *@param broker The broker object returned from an earlier call to addBroker.
+ */
+ void delBroker(Broker* broker);
+
+ /** Get a list of known management packages
+ *
+ *@param packages Vector of package names returned by the session manager.
+ */
+ void getPackages(NameVector& packages);
+
+ /** Get a list of class keys associated with a package
+ *
+ *@param classKeys List of class keys returned by the session manager.
+ *@param packageName Name of package being queried.
+ */
+ void getClasses(KeyVector& classKeys, const std::string& packageName);
+
+ /** Get the schema of a class given its class key
+ *
+ *@param classKey Class key of the desired schema.
+ */
+ SchemaClass& getSchema(const ClassKey& classKey);
+
+ /** Request that updates be received for all classes within a package
+ *
+ * Note that this method is only meaningful if a ConsoleListener was provided at session
+ * creation and if the 'userBindings' flag was set to true.
+ *
+ *@param packageName Name of the package to which to bind.
+ */
+ void bindPackage(const std::string& packageName);
+
+ /** Request update to be received for a particular class
+ *
+ * Note that this method is only meaningful if a ConsoleListener was provided at session
+ * creation and if the 'userBindings' flag was set to true.
+ *
+ *@param classKey Class key of class to which to bind.
+ */
+ void bindClass(const ClassKey& classKey);
+ void bindClass(const std::string& packageName, const std::string& className);
+
+ /** Get a list of qmf agents known to the session manager.
+ *
+ *@param agents Vector of Agent objects returned by the session manager.
+ *@param broker Return agents registered with this broker only. If NULL, return agents
+ * from all connected brokers.
+ */
+ void getAgents(Agent::Vector& agents, Broker* broker = 0);
+
+ /** Get objects from agents. There are four variants of this method with different ways of
+ * specifying from which class objects are being queried.
+ *
+ *@param objects List of objects received.
+ *@param classKey ClassKey object identifying class to be queried.
+ *@param className Class name identifying class to be queried.
+ *@param objectId Object Id of the single object to be queried.
+ *@param broker Restrict the query to this broker, or all brokers if NULL.
+ *@param agent Restrict the query to this agent, or all agents if NULL.
+ */
+ void getObjects(Object::Vector& objects, const std::string& className,
+ Broker* broker = 0, Agent* agent = 0);
+ //void getObjects(Object::Vector& objects, const ClassKey& classKey,
+ // Broker* broker = 0, Agent* agent = 0);
+ //void getObjects(Object::Vector& objects, const ObjectId& objectId,
+ // Broker* broker = 0, Agent* agent = 0);
+
+private:
+ friend class Broker;
+ friend class Broker::ConnectionThread;
+ friend class Object;
+ sys::Mutex lock;
+ sys::Mutex brokerListLock;
+ ConsoleListener* listener;
+ std::vector<Broker*> brokers;
+ std::map<std::string, Package*> packages;
+ SequenceManager sequenceManager;
+ sys::Condition cv;
+ SequenceManager::set syncSequenceList;
+ Object::Vector getResult;
+ std::string error;
+ Settings settings;
+ NameVector bindingKeyList;
+
+ void bindingKeys();
+ void allBrokersStable();
+ void startProtocol(Broker* broker);
+ void handleBrokerResp(Broker* broker, framing::Buffer& inBuffer, uint32_t sequence);
+ void handlePackageInd(Broker* broker, framing::Buffer& inBuffer, uint32_t sequence);
+ void handleCommandComplete(Broker* broker, framing::Buffer& inBuffer, uint32_t sequence);
+ void handleClassInd(Broker* broker, framing::Buffer& inBuffer, uint32_t sequence);
+ void handleMethodResp(Broker* broker, framing::Buffer& inBuffer, uint32_t sequence);
+ void handleHeartbeatInd(Broker* broker, framing::Buffer& inBuffer, uint32_t sequence);
+ void handleEventInd(Broker* broker, framing::Buffer& inBuffer, uint32_t sequence);
+ void handleSchemaResp(Broker* broker, framing::Buffer& inBuffer, uint32_t sequence);
+ void handleContentInd(Broker* broker, framing::Buffer& inBuffer, uint32_t sequence, bool prop, bool stat);
+ void handleBrokerConnect(Broker* broker);
+ void handleBrokerDisconnect(Broker* broker);
+
+};
+
+}} // namespace qpid::console
+
+#endif /*!_QPID_CONSOLE_SESSION_MANAGER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/console/Value.cpp b/RC9/qpid/cpp/src/qpid/console/Value.cpp
new file mode 100644
index 0000000000..532709ab05
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/console/Value.cpp
@@ -0,0 +1,168 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Value.h"
+#include "qpid/framing/Buffer.h"
+
+using namespace qpid::console;
+using namespace std;
+
+string NullValue::str() const
+{
+ return "<Null>";
+}
+
+RefValue::RefValue(framing::Buffer& buffer)
+{
+ uint64_t first = buffer.getLongLong();
+ uint64_t second = buffer.getLongLong();
+ value.setValue(first, second);
+}
+
+string RefValue::str() const
+{
+ stringstream s;
+ s << value;
+ return s.str();
+}
+
+string UintValue::str() const
+{
+ stringstream s;
+ s << value;
+ return s.str();
+}
+
+string IntValue::str() const
+{
+ stringstream s;
+ s << value;
+ return s.str();
+}
+
+string Uint64Value::str() const
+{
+ stringstream s;
+ s << value;
+ return s.str();
+}
+
+string Int64Value::str() const
+{
+ stringstream s;
+ s << value;
+ return s.str();
+}
+
+StringValue::StringValue(framing::Buffer& buffer, int tc)
+{
+ if (tc == 6)
+ buffer.getShortString(value);
+ else
+ buffer.getMediumString(value);
+}
+
+string BoolValue::str() const
+{
+ return value ? "T" : "F";
+}
+
+string FloatValue::str() const
+{
+ stringstream s;
+ s << value;
+ return s.str();
+}
+
+string DoubleValue::str() const
+{
+ stringstream s;
+ s << value;
+ return s.str();
+}
+
+UuidValue::UuidValue(framing::Buffer& buffer)
+{
+ value.decode(buffer);
+}
+
+string MapValue::str() const
+{
+ stringstream s;
+ s << value;
+ return s.str();
+}
+
+MapValue::MapValue(framing::Buffer& buffer)
+{
+ value.decode(buffer);
+}
+
+
+Value::Ptr ValueFactory::newValue(int typeCode, framing::Buffer& buffer)
+{
+ switch (typeCode) {
+ case 1: return Value::Ptr(new UintValue(buffer.getOctet())); // U8
+ case 2: return Value::Ptr(new UintValue(buffer.getShort())); // U16
+ case 3: return Value::Ptr(new UintValue(buffer.getLong())); // U32
+ case 4: return Value::Ptr(new Uint64Value(buffer.getLongLong())); // U64
+ case 6: return Value::Ptr(new StringValue(buffer, 6)); // SSTR
+ case 7: return Value::Ptr(new StringValue(buffer, 7)); // LSTR
+ case 8: return Value::Ptr(new Int64Value(buffer.getLongLong())); // ABSTIME
+ case 9: return Value::Ptr(new Uint64Value(buffer.getLongLong())); // DELTATIME
+ case 10: return Value::Ptr(new RefValue(buffer)); // REF
+ case 11: return Value::Ptr(new BoolValue(buffer.getOctet())); // BOOL
+ case 12: return Value::Ptr(new FloatValue(buffer.getFloat())); // FLOAT
+ case 13: return Value::Ptr(new DoubleValue(buffer.getDouble())); // DOUBLE
+ case 14: return Value::Ptr(new UuidValue(buffer)); // UUID
+ case 15: return Value::Ptr(new MapValue(buffer)); // MAP
+ case 16: return Value::Ptr(new IntValue(buffer.getOctet())); // S8
+ case 17: return Value::Ptr(new IntValue(buffer.getShort())); // S16
+ case 18: return Value::Ptr(new IntValue(buffer.getLong())); // S32
+ case 19: return Value::Ptr(new Int64Value(buffer.getLongLong())); // S64
+ }
+
+ return Value::Ptr();
+}
+
+void ValueFactory::encodeValue(int typeCode, Value::Ptr value, framing::Buffer& buffer)
+{
+ switch (typeCode) {
+ case 1: buffer.putOctet(value->asUint()); return; // U8
+ case 2: buffer.putShort(value->asUint()); return; // U16
+ case 3: buffer.putLong(value->asUint()); return; // U32
+ case 4: buffer.putLongLong(value->asUint64()); return; // U64
+ case 6: buffer.putShortString(value->asString()); return; // SSTR
+ case 7: buffer.putMediumString(value->asString()); return; // LSTR
+ case 8: buffer.putLongLong(value->asInt64()); return; // ABSTIME
+ case 9: buffer.putLongLong(value->asUint64()); return; // DELTATIME
+ case 10: value->asObjectId().encode(buffer); return; // REF
+ case 11: buffer.putOctet(value->asBool() ? 1 : 0); return; // BOOL
+ case 12: buffer.putFloat(value->asFloat()); return; // FLOAT
+ case 13: buffer.putDouble(value->asDouble()); return; // DOUBLE
+ case 14: value->asUuid().encode(buffer); return; // UUID
+ case 15: value->asMap().encode(buffer); return; // MAP
+ case 16: buffer.putOctet(value->asInt()); return; // S8
+ case 17: buffer.putShort(value->asInt()); return; // S16
+ case 18: buffer.putLong(value->asInt()); return; // S32
+ case 19: buffer.putLongLong(value->asInt64()); return; // S64
+ }
+}
diff --git a/RC9/qpid/cpp/src/qpid/console/Value.h b/RC9/qpid/cpp/src/qpid/console/Value.h
new file mode 100644
index 0000000000..5a0915c69b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/console/Value.h
@@ -0,0 +1,207 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _QPID_CONSOLE_VALUE_H_
+#define _QPID_CONSOLE_VALUE_H_
+
+#include "qpid/Exception.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/framing/FieldTable.h"
+#include "ObjectId.h"
+#include <boost/shared_ptr.hpp>
+
+namespace qpid {
+namespace framing {
+ class Buffer;
+}
+namespace console {
+
+ /**
+ * \ingroup qmfconsoleapi
+ */
+ class Value {
+
+ public:
+ typedef boost::shared_ptr<Value> Ptr;
+ virtual ~Value() {}
+ virtual std::string str() const = 0;
+
+ virtual bool isNull() const { return false; }
+ virtual bool isObjectId() const { return false; }
+ virtual bool isUint() const { return false; }
+ virtual bool isInt() const { return false; }
+ virtual bool isUint64() const { return false; }
+ virtual bool isInt64() const { return false; }
+ virtual bool isString() const { return false; }
+ virtual bool isBool() const { return false; }
+ virtual bool isFloat() const { return false; }
+ virtual bool isDouble() const { return false; }
+ virtual bool isUuid() const { return false; }
+ virtual bool isMap() const { return false; }
+
+ virtual ObjectId asObjectId() const { incompatible(); return ObjectId(); }
+ virtual uint32_t asUint() const { incompatible(); return 0; }
+ virtual int32_t asInt() const { incompatible(); return 0; }
+ virtual uint64_t asUint64() const { incompatible(); return 0; }
+ virtual int64_t asInt64() const { incompatible(); return 0; }
+ virtual std::string asString() const { incompatible(); return std::string(); }
+ virtual bool asBool() const { incompatible(); return false; }
+ virtual float asFloat() const { incompatible(); return 0.0; }
+ virtual double asDouble() const { incompatible(); return 0.0; }
+ virtual framing::Uuid asUuid() const { incompatible(); return framing::Uuid(); }
+ virtual framing::FieldTable asMap() const { incompatible(); return framing::FieldTable(); }
+
+ private:
+ void incompatible() const {
+ throw Exception("Incompatible Type");
+ }
+ };
+
+ class NullValue : public Value {
+ public:
+ NullValue() {}
+ std::string str() const;
+ bool isNull() const { return true; }
+ };
+
+ class RefValue : public Value {
+ public:
+ RefValue(ObjectId v) : value(v) {}
+ RefValue(framing::Buffer& buffer);
+ std::string str() const;
+ bool isObjectId() const { return true; }
+ ObjectId asObjectId() const { return value; }
+ private:
+ ObjectId value;
+ };
+
+ class UintValue : public Value {
+ public:
+ UintValue(uint32_t v) : value(v) {}
+ std::string str() const;
+ bool isUint() const { return true; }
+ uint32_t asUint() const { return value; }
+ private:
+ uint32_t value;
+ };
+
+ class IntValue : public Value {
+ public:
+ IntValue(int32_t v) : value(v) {}
+ std::string str() const;
+ bool isInt() const { return true; }
+ int32_t asInt() const { return value; }
+ private:
+ int32_t value;
+ };
+
+ class Uint64Value : public Value {
+ public:
+ Uint64Value(uint64_t v) : value(v) {}
+ std::string str() const;
+ bool isUint64() const { return true; }
+ uint64_t asUint64() const { return value; }
+ private:
+ uint64_t value;
+ };
+
+ class Int64Value : public Value {
+ public:
+ Int64Value(int64_t v) : value(v) {}
+ std::string str() const;
+ bool isInt64() const { return true; }
+ int64_t asInt64() const { return value; }
+ private:
+ int64_t value;
+ };
+
+ class StringValue : public Value {
+ public:
+ StringValue(const std::string& v) : value(v) {}
+ StringValue(framing::Buffer& buffer, int tc);
+ std::string str() const { return value; }
+ bool isString() const { return true; }
+ std::string asString() const { return value; }
+ private:
+ std::string value;
+ };
+
+ class BoolValue : public Value {
+ public:
+ BoolValue(bool v) : value(v) {}
+ BoolValue(uint8_t v) : value(v != 0) {}
+ std::string str() const;
+ bool isBool() const { return true; }
+ bool asBool() const { return value; }
+ private:
+ bool value;
+ };
+
+ class FloatValue : public Value {
+ public:
+ FloatValue(float v) : value(v) {}
+ std::string str() const;
+ bool isFloat() const { return true; }
+ float asFloat() const { return value; }
+ private:
+ float value;
+ };
+
+ class DoubleValue : public Value {
+ public:
+ DoubleValue(double v) : value(v) {}
+ std::string str() const;
+ bool isDouble() const { return true; }
+ double asDouble() const { return value; }
+ private:
+ double value;
+ };
+
+ class UuidValue : public Value {
+ public:
+ UuidValue(const framing::Uuid& v) : value(v) {}
+ UuidValue(framing::Buffer& buffer);
+ std::string str() const { return value.str(); }
+ bool isUuid() const { return true; }
+ framing::Uuid asUuid() const { return value; }
+ private:
+ framing::Uuid value;
+ };
+
+ class MapValue : public Value {
+ public:
+ MapValue(const framing::FieldTable& v) : value(v) {}
+ MapValue(framing::Buffer& buffer);
+ std::string str() const;
+ bool isMap() const { return true; }
+ framing::FieldTable asMap() const { return value; }
+ private:
+ framing::FieldTable value;
+ };
+
+ class ValueFactory {
+ public:
+ static Value::Ptr newValue(int typeCode, framing::Buffer& buffer);
+ static void encodeValue(int typeCode, Value::Ptr value, framing::Buffer& buffer);
+ };
+}
+}
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/framing/AMQBody.cpp b/RC9/qpid/cpp/src/qpid/framing/AMQBody.cpp
new file mode 100644
index 0000000000..b3eeae0615
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/AMQBody.cpp
@@ -0,0 +1,64 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/framing/AMQBody.h"
+#include "qpid/framing/AMQMethodBody.h"
+#include "qpid/framing/AMQHeaderBody.h"
+#include "qpid/framing/AMQContentBody.h"
+#include "qpid/framing/AMQHeartbeatBody.h"
+#include <iostream>
+
+namespace qpid {
+namespace framing {
+
+std::ostream& operator<<(std::ostream& out, const AMQBody& body)
+{
+ body.print(out);
+ return out;
+}
+
+AMQBody::~AMQBody() {}
+
+namespace {
+struct MatchBodies : public AMQBodyConstVisitor {
+ const AMQBody& body;
+ bool match;
+
+ MatchBodies(const AMQBody& b) : body(b), match(false) {}
+ virtual ~MatchBodies() {}
+
+ virtual void visit(const AMQHeaderBody&) { match=dynamic_cast<const AMQHeaderBody*>(&body); }
+ virtual void visit(const AMQContentBody&) { match=dynamic_cast<const AMQContentBody*>(&body); }
+ virtual void visit(const AMQHeartbeatBody&) { match=dynamic_cast<const AMQHeartbeatBody*>(&body); }
+ virtual void visit(const AMQMethodBody& x) {
+ const AMQMethodBody* y=dynamic_cast<const AMQMethodBody*>(&body);
+ match = (y && y->amqpMethodId() == x.amqpMethodId() && y->amqpClassId() == x.amqpClassId());
+ }
+};
+
+}
+bool AMQBody::match(const AMQBody& a, const AMQBody& b) {
+ MatchBodies matcher(a);
+ b.accept(matcher);
+ return matcher.match;
+}
+
+}} // namespace
diff --git a/RC9/qpid/cpp/src/qpid/framing/AMQBody.h b/RC9/qpid/cpp/src/qpid/framing/AMQBody.h
new file mode 100644
index 0000000000..93f4319575
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/AMQBody.h
@@ -0,0 +1,78 @@
+#ifndef QPID_FRAMING_AMQBODY_H
+#define QPID_FRAMING_AMQBODY_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/framing/amqp_types.h"
+
+#include <ostream>
+
+namespace qpid {
+namespace framing {
+
+class Buffer;
+
+class AMQMethodBody;
+class AMQHeaderBody;
+class AMQContentBody;
+class AMQHeartbeatBody;
+
+struct AMQBodyConstVisitor {
+ virtual ~AMQBodyConstVisitor() {}
+ virtual void visit(const AMQHeaderBody&) = 0;
+ virtual void visit(const AMQContentBody&) = 0;
+ virtual void visit(const AMQHeartbeatBody&) = 0;
+ virtual void visit(const AMQMethodBody&) = 0;
+};
+
+class AMQBody
+{
+ public:
+ virtual ~AMQBody();
+
+ virtual uint8_t type() const = 0;
+
+ virtual void encode(Buffer& buffer) const = 0;
+ virtual void decode(Buffer& buffer, uint32_t=0) = 0;
+ virtual uint32_t encodedSize() const = 0;
+
+ virtual void print(std::ostream& out) const = 0;
+ virtual void accept(AMQBodyConstVisitor&) const = 0;
+
+ virtual AMQMethodBody* getMethod() { return 0; }
+ virtual const AMQMethodBody* getMethod() const { return 0; }
+
+ /** Match if same type and same class/method ID for methods */
+ static bool match(const AMQBody& , const AMQBody& );
+};
+
+std::ostream& operator<<(std::ostream& out, const AMQBody& body) ;
+
+enum BodyTypes {
+ METHOD_BODY = 1,
+ HEADER_BODY = 2,
+ CONTENT_BODY = 3,
+ HEARTBEAT_BODY = 8
+};
+
+}} // namespace qpid::framing
+
+#endif /*!QPID_FRAMING_AMQBODY_H*/
diff --git a/RC9/qpid/cpp/src/qpid/framing/AMQCommandControlBody.h b/RC9/qpid/cpp/src/qpid/framing/AMQCommandControlBody.h
new file mode 100644
index 0000000000..d12b70a168
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/AMQCommandControlBody.h
@@ -0,0 +1,70 @@
+#ifndef QPID_FRAMING_AMQCOMMANDCONTROLBODY_H
+#define QPID_FRAMING_AMQCOMMANDCONTROLBODY_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/amqp_0_10/helpers.h"
+#include "qpid/framing/AMQBody.h"
+
+namespace qpid {
+namespace framing {
+
+/**
+ * AMQBody wrapper for Command and Control.
+ * Temporary measure to fit with old code.
+ */
+template <class T> class AMQCommandControlBody : public AMQBody, public T
+{
+ public:
+ virtual uint8_t type() const { return 100+T::SEGMENT_TYPE; }
+
+ virtual void encode(Buffer& buffer) const {
+ Codec::encode(buffer.getIterator(), static_cast<const T&>(*this));
+ }
+ virtual void decode(Buffer& buffer, uint32_t=0) {
+ Codec::decode(buffer.getIterator(), static_cast<T&>(*this));
+ }
+ virtual uint32_t encodedSize() const {
+ Codec::size(buffer.getIterator(), static_cast<const T&>(*this));
+ }
+
+ virtual void print(std::ostream& out) const {
+ out << static_cast<const T&>(*this) << endl;
+ }
+ virtual void AMQBody::accept(AMQBodyConstVisitor&) const { assert(0); }
+};
+
+class CommandBody : public AMQCommandControlBody<amqp_0_10::Command> {
+ using Command::accept; // Hide AMQBody::accept
+ virtual Command* getCommand() { return this; }
+ virtual const Command* getCommand() const { return this; }
+};
+
+class ControlBody : public AMQCommandControlBody<amqp_0_10::Control> {
+ using Control::accept; // Hide AMQBody::accept
+ virtual Control* getControl() { return this; }
+ virtual const Control* getControl() const { return this; }
+};
+
+}} // namespace qpid::framing
+
+#endif /*!QPID_FRAMING_AMQCOMMANDCONTROLBODY_H*/
diff --git a/RC9/qpid/cpp/src/qpid/framing/AMQContentBody.cpp b/RC9/qpid/cpp/src/qpid/framing/AMQContentBody.cpp
new file mode 100644
index 0000000000..85fb95739b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/AMQContentBody.cpp
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "AMQContentBody.h"
+#include <iostream>
+
+qpid::framing::AMQContentBody::AMQContentBody(){
+}
+
+qpid::framing::AMQContentBody::AMQContentBody(const string& _data) : data(_data){
+}
+
+uint32_t qpid::framing::AMQContentBody::encodedSize() const{
+ return data.size();
+}
+void qpid::framing::AMQContentBody::encode(Buffer& buffer) const{
+ buffer.putRawData(data);
+}
+void qpid::framing::AMQContentBody::decode(Buffer& buffer, uint32_t _size){
+ buffer.getRawData(data, _size);
+}
+
+void qpid::framing::AMQContentBody::print(std::ostream& out) const
+{
+ out << "content (" << encodedSize() << " bytes)";
+ out << " " << data.substr(0,16) << "...";
+}
diff --git a/RC9/qpid/cpp/src/qpid/framing/AMQContentBody.h b/RC9/qpid/cpp/src/qpid/framing/AMQContentBody.h
new file mode 100644
index 0000000000..288f1549a9
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/AMQContentBody.h
@@ -0,0 +1,53 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "amqp_types.h"
+#include "AMQBody.h"
+#include "Buffer.h"
+
+#ifndef _AMQContentBody_
+#define _AMQContentBody_
+
+namespace qpid {
+namespace framing {
+
+class AMQContentBody : public AMQBody
+{
+ string data;
+
+public:
+ AMQContentBody();
+ AMQContentBody(const string& data);
+ inline virtual ~AMQContentBody(){}
+ inline uint8_t type() const { return CONTENT_BODY; };
+ inline const string& getData() const { return data; }
+ inline string& getData() { return data; }
+ uint32_t encodedSize() const;
+ void encode(Buffer& buffer) const;
+ void decode(Buffer& buffer, uint32_t size);
+ void print(std::ostream& out) const;
+ void accept(AMQBodyConstVisitor& v) const { v.visit(*this); }
+};
+
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/framing/AMQDataBlock.h b/RC9/qpid/cpp/src/qpid/framing/AMQDataBlock.h
new file mode 100644
index 0000000000..0b1f459627
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/AMQDataBlock.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "Buffer.h"
+
+#ifndef _AMQDataBlock_
+#define _AMQDataBlock_
+
+namespace qpid {
+namespace framing {
+
+class AMQDataBlock
+{
+public:
+ virtual ~AMQDataBlock() {}
+ virtual void encode(Buffer& buffer) const = 0;
+ virtual bool decode(Buffer& buffer) = 0;
+ virtual uint32_t encodedSize() const = 0;
+};
+
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/framing/AMQFrame.cpp b/RC9/qpid/cpp/src/qpid/framing/AMQFrame.cpp
new file mode 100644
index 0000000000..98a1354811
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/AMQFrame.cpp
@@ -0,0 +1,124 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "AMQFrame.h"
+
+#include "qpid/framing/variant.h"
+#include "qpid/framing/AMQMethodBody.h"
+#include "qpid/framing/reply_exceptions.h"
+
+#include <boost/format.hpp>
+
+#include <iostream>
+
+namespace qpid {
+namespace framing {
+
+AMQFrame::~AMQFrame() {}
+
+void AMQFrame::setBody(const AMQBody& b) { body = new BodyHolder(b); }
+
+void AMQFrame::setMethod(ClassId c, MethodId m) { body = new BodyHolder(c,m); }
+
+uint32_t AMQFrame::encodedSize() const {
+ return frameOverhead() + body->encodedSize();
+}
+
+uint32_t AMQFrame::frameOverhead() {
+ return 12 /*frame header*/;
+}
+
+uint16_t AMQFrame::DECODE_SIZE_MIN=4;
+
+uint16_t AMQFrame::decodeSize(char* data) {
+ Buffer buf(data+2, DECODE_SIZE_MIN);
+ return buf.getShort();
+}
+
+void AMQFrame::encode(Buffer& buffer) const
+{
+ //set track first (controls on track 0, everything else on 1):
+ uint8_t track = getBody()->type() ? 1 : 0;
+
+ uint8_t flags = (bof ? 0x08 : 0) | (eof ? 0x04 : 0) | (bos ? 0x02 : 0) | (eos ? 0x01 : 0);
+ buffer.putOctet(flags);
+ buffer.putOctet(getBody()->type());
+ buffer.putShort(encodedSize());
+ buffer.putOctet(0);
+ buffer.putOctet(0x0f & track);
+ buffer.putShort(channel);
+ buffer.putLong(0);
+ body->encode(buffer);
+}
+
+bool AMQFrame::decode(Buffer& buffer)
+{
+ if(buffer.available() < frameOverhead())
+ return false;
+ buffer.record();
+
+ uint8_t flags = buffer.getOctet();
+ uint8_t framing_version = (flags & 0xc0) >> 6;
+ if (framing_version != 0)
+ throw FramingErrorException(QPID_MSG("Framing version unsupported"));
+ bof = flags & 0x08;
+ eof = flags & 0x04;
+ bos = flags & 0x02;
+ eos = flags & 0x01;
+ uint8_t type = buffer.getOctet();
+ uint16_t frame_size = buffer.getShort();
+ if (frame_size < frameOverhead())
+ throw FramingErrorException(QPID_MSG("Frame size too small " << frame_size));
+ uint8_t reserved1 = buffer.getOctet();
+ uint8_t field1 = buffer.getOctet();
+ subchannel = field1 & 0x0f;
+ channel = buffer.getShort();
+ (void) buffer.getLong(); // reserved2
+
+ // Verify that the protocol header meets current spec
+ // TODO: should we check reserved2 against zero as well? - the
+ // spec isn't clear
+ if ((flags & 0x30) != 0 || reserved1 != 0 || (field1 & 0xf0) != 0)
+ throw FramingErrorException(QPID_MSG("Reserved bits not zero"));
+
+ // TODO: should no longer care about body size and only pass up
+ // B,E,b,e flags
+ uint16_t body_size = frame_size - frameOverhead();
+ if (buffer.available() < body_size){
+ buffer.restore();
+ return false;
+ }
+ body = new BodyHolder();
+ body->decode(type,buffer, body_size);
+ return true;
+}
+
+std::ostream& operator<<(std::ostream& out, const AMQFrame& f)
+{
+ return
+ out << "Frame["
+ << (f.getBof() ? "B" : "") << (f.getEof() ? "E" : "")
+ << (f.getBos() ? "b" : "") << (f.getEos() ? "e" : "") << "; "
+ << "channel=" << f.getChannel() << "; " << *f.getBody()
+ << "]";
+}
+
+
+}} // namespace qpid::framing
diff --git a/RC9/qpid/cpp/src/qpid/framing/AMQFrame.h b/RC9/qpid/cpp/src/qpid/framing/AMQFrame.h
new file mode 100644
index 0000000000..ddfe438806
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/AMQFrame.h
@@ -0,0 +1,128 @@
+#ifndef _AMQFrame_
+#define _AMQFrame_
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "AMQDataBlock.h"
+#include "AMQHeaderBody.h"
+#include "AMQContentBody.h"
+#include "AMQHeartbeatBody.h"
+#include "ProtocolVersion.h"
+#include "BodyHolder.h"
+
+#include <boost/intrusive_ptr.hpp>
+#include <boost/cast.hpp>
+
+namespace qpid {
+namespace framing {
+
+class BodyHolder;
+
+class AMQFrame : public AMQDataBlock
+{
+ public:
+ AMQFrame(boost::intrusive_ptr<BodyHolder> b=0) : body(b) { init(); }
+ AMQFrame(const AMQBody& b) { setBody(b); init(); }
+ ~AMQFrame();
+
+ template <class InPlace>
+ AMQFrame(const InPlace& ip, typename EnableInPlace<InPlace>::type* =0) {
+ init(); setBody(ip);
+ }
+
+ ChannelId getChannel() const { return channel; }
+ void setChannel(ChannelId c) { channel = c; }
+
+ boost::intrusive_ptr<BodyHolder> getHolder() { return body; }
+
+ AMQBody* getBody() { return body ? body->get() : 0; }
+ const AMQBody* getBody() const { return body ? body->get() : 0; }
+
+ AMQMethodBody* getMethod() { return getBody()->getMethod(); }
+ const AMQMethodBody* getMethod() const { return getBody()->getMethod(); }
+
+ void setBody(const AMQBody& b);
+
+ template <class InPlace>
+ typename EnableInPlace<InPlace>::type setBody(const InPlace& ip) {
+ body = new BodyHolder(ip);
+ }
+
+ void setMethod(ClassId c, MethodId m);
+
+ template <class T> T* castBody() {
+ return boost::polymorphic_downcast<T*>(getBody());
+ }
+
+ template <class T> const T* castBody() const {
+ return boost::polymorphic_downcast<const T*>(getBody());
+ }
+
+ void encode(Buffer& buffer) const;
+ bool decode(Buffer& buffer);
+ uint32_t encodedSize() const;
+
+ // 0-10 terminology: first/last frame (in segment) first/last segment (in assembly)
+
+ bool isFirstSegment() const { return bof; }
+ bool isLastSegment() const { return eof; }
+ bool isFirstFrame() const { return bos; }
+ bool isLastFrame() const { return eos; }
+
+ void setFirstSegment(bool set=true) { bof = set; }
+ void setLastSegment(bool set=true) { eof = set; }
+ void setFirstFrame(bool set=true) { bos = set; }
+ void setLastFrame(bool set=true) { eos = set; }
+
+ // 0-9 terminology: beginning/end of frameset, beginning/end of segment.
+
+ bool getBof() const { return bof; }
+ void setBof(bool isBof) { bof = isBof; }
+ bool getEof() const { return eof; }
+ void setEof(bool isEof) { eof = isEof; }
+
+ bool getBos() const { return bos; }
+ void setBos(bool isBos) { bos = isBos; }
+ bool getEos() const { return eos; }
+ void setEos(bool isEos) { eos = isEos; }
+
+ static uint16_t DECODE_SIZE_MIN;
+ static uint32_t frameOverhead();
+ /** Must point to at least DECODE_SIZE_MIN bytes of data */
+ static uint16_t decodeSize(char* data);
+ private:
+ void init() { bof = eof = bos = eos = true; subchannel=0; channel=0; }
+
+ boost::intrusive_ptr<BodyHolder> body;
+ uint16_t channel : 16;
+ uint8_t subchannel : 8;
+ bool bof : 1;
+ bool eof : 1;
+ bool bos : 1;
+ bool eos : 1;
+};
+
+std::ostream& operator<<(std::ostream&, const AMQFrame&);
+
+}} // namespace qpid::framing
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/framing/AMQHeaderBody.cpp b/RC9/qpid/cpp/src/qpid/framing/AMQHeaderBody.cpp
new file mode 100644
index 0000000000..276418b208
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/AMQHeaderBody.cpp
@@ -0,0 +1,63 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "AMQHeaderBody.h"
+#include "qpid/Exception.h"
+#include "qpid/log/Statement.h"
+
+uint32_t qpid::framing::AMQHeaderBody::encodedSize() const {
+ return properties.encodedSize();
+}
+
+void qpid::framing::AMQHeaderBody::encode(Buffer& buffer) const {
+ properties.encode(buffer);
+}
+
+void qpid::framing::AMQHeaderBody::decode(Buffer& buffer, uint32_t size) {
+ uint32_t limit = buffer.available() - size;
+ while (buffer.available() > limit + 2) {
+ uint32_t len = buffer.getLong();
+ uint16_t type = buffer.getShort();
+ if (!properties.decode(buffer, len, type)) {
+ // TODO: should just skip & keep for later dispatch.
+ throw Exception(QPID_MSG("Unexpected property type: " << type));
+ }
+ }
+}
+
+uint64_t qpid::framing::AMQHeaderBody::getContentLength() const
+{
+ const MessageProperties* mProps = get<MessageProperties>();
+ if (mProps)
+ return mProps->getContentLength();
+ return 0;
+}
+
+void qpid::framing::AMQHeaderBody::print(std::ostream& out) const
+{
+ out << "header (" << encodedSize() << " bytes)";
+ out << "; properties={";
+ properties.print(out);
+ out << "}";
+}
+
+void qpid::framing::AMQHeaderBody::accept(AMQBodyConstVisitor& v) const {
+ v.visit(*this);
+}
diff --git a/RC9/qpid/cpp/src/qpid/framing/AMQHeaderBody.h b/RC9/qpid/cpp/src/qpid/framing/AMQHeaderBody.h
new file mode 100644
index 0000000000..7ddb7d89cf
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/AMQHeaderBody.h
@@ -0,0 +1,108 @@
+#ifndef QPID_FRAMING_AMQHEADERBODY_H
+#define QPID_FRAMING_AMQHEADERBODY_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "amqp_types.h"
+#include "AMQBody.h"
+#include "Buffer.h"
+#include "qpid/framing/DeliveryProperties.h"
+#include "qpid/framing/MessageProperties.h"
+#include <iostream>
+
+#include <boost/optional.hpp>
+
+
+namespace qpid {
+namespace framing {
+
+enum DeliveryMode { TRANSIENT = 1, PERSISTENT = 2};
+
+class AMQHeaderBody : public AMQBody
+{
+ template <class T> struct OptProps { boost::optional<T> props; };
+ template <class Base, class T>
+ struct PropSet : public Base, public OptProps<T> {
+ uint32_t encodedSize() const {
+ const boost::optional<T>& p=this->OptProps<T>::props;
+ return (p ? p->encodedSize() : 0) + Base::encodedSize();
+ }
+ void encode(Buffer& buffer) const {
+ const boost::optional<T>& p=this->OptProps<T>::props;
+ if (p) p->encode(buffer);
+ Base::encode(buffer);
+ }
+ bool decode(Buffer& buffer, uint32_t size, uint16_t type) {
+ boost::optional<T>& p=this->OptProps<T>::props;
+ if (type == T::TYPE) {
+ p=T();
+ p->decodeStructBody(buffer, size);
+ return true;
+ }
+ else
+ return Base::decode(buffer, size, type);
+ }
+ void print(std::ostream& out) const {
+ const boost::optional<T>& p=this->OptProps<T>::props;
+ if (p) out << *p;
+ Base::print(out);
+ }
+ };
+
+ struct Empty {
+ uint32_t encodedSize() const { return 0; }
+ void encode(Buffer&) const {};
+ bool decode(Buffer&, uint32_t, uint16_t) const { return false; };
+ void print(std::ostream&) const {}
+ };
+
+ // Could use boost::mpl::fold to construct a larger set.
+ typedef PropSet<PropSet<Empty, DeliveryProperties>, MessageProperties> Properties;
+
+ Properties properties;
+
+public:
+
+ inline uint8_t type() const { return HEADER_BODY; }
+
+ uint32_t encodedSize() const;
+ void encode(Buffer& buffer) const;
+ void decode(Buffer& buffer, uint32_t size);
+ uint64_t getContentLength() const;
+ void print(std::ostream& out) const;
+ void accept(AMQBodyConstVisitor&) const;
+
+ template <class T> T* get(bool create) {
+ boost::optional<T>& p=properties.OptProps<T>::props;
+ if (create && !p) p=T();
+ return p.get_ptr();
+ }
+
+ template <class T> const T* get() const {
+ return properties.OptProps<T>::props.get_ptr();
+ }
+};
+
+}}
+
+
+
+#endif /*!QPID_FRAMING_AMQHEADERBODY_H*/
diff --git a/RC9/qpid/cpp/src/qpid/framing/AMQHeartbeatBody.cpp b/RC9/qpid/cpp/src/qpid/framing/AMQHeartbeatBody.cpp
new file mode 100644
index 0000000000..140ce2e794
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/AMQHeartbeatBody.cpp
@@ -0,0 +1,29 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "AMQHeartbeatBody.h"
+#include <iostream>
+
+qpid::framing::AMQHeartbeatBody::~AMQHeartbeatBody() {}
+
+void qpid::framing::AMQHeartbeatBody::print(std::ostream& out) const {
+ out << "heartbeat";
+}
diff --git a/RC9/qpid/cpp/src/qpid/framing/AMQHeartbeatBody.h b/RC9/qpid/cpp/src/qpid/framing/AMQHeartbeatBody.h
new file mode 100644
index 0000000000..7b42b46e5c
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/AMQHeartbeatBody.h
@@ -0,0 +1,46 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "amqp_types.h"
+#include "AMQBody.h"
+#include "Buffer.h"
+
+#ifndef _AMQHeartbeatBody_
+#define _AMQHeartbeatBody_
+
+namespace qpid {
+namespace framing {
+
+class AMQHeartbeatBody : public AMQBody
+{
+public:
+ virtual ~AMQHeartbeatBody();
+ inline uint32_t encodedSize() const { return 0; }
+ inline uint8_t type() const { return HEARTBEAT_BODY; }
+ inline void encode(Buffer& ) const {}
+ inline void decode(Buffer& , uint32_t /*size*/) {}
+ virtual void print(std::ostream& out) const;
+ void accept(AMQBodyConstVisitor& v) const { v.visit(*this); }
+};
+
+}
+}
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/framing/AMQMethodBody.cpp b/RC9/qpid/cpp/src/qpid/framing/AMQMethodBody.cpp
new file mode 100644
index 0000000000..924d906d43
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/AMQMethodBody.cpp
@@ -0,0 +1,28 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "AMQMethodBody.h"
+
+namespace qpid {
+namespace framing {
+
+AMQMethodBody::~AMQMethodBody() {}
+
+}} // namespace qpid::framing
diff --git a/RC9/qpid/cpp/src/qpid/framing/AMQMethodBody.h b/RC9/qpid/cpp/src/qpid/framing/AMQMethodBody.h
new file mode 100644
index 0000000000..cc7489ddd9
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/AMQMethodBody.h
@@ -0,0 +1,72 @@
+#ifndef _AMQMethodBody_
+#define _AMQMethodBody_
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "amqp_types.h"
+#include "AMQBody.h"
+#include "qpid/framing/ProtocolVersion.h"
+#include "qpid/shared_ptr.h"
+
+#include <ostream>
+
+#include <assert.h>
+
+namespace qpid {
+namespace framing {
+
+class Buffer;
+class AMQP_ServerOperations;
+class MethodBodyConstVisitor;
+
+class AMQMethodBody : public AMQBody {
+ public:
+ AMQMethodBody() {}
+ virtual ~AMQMethodBody();
+
+ virtual void accept(MethodBodyConstVisitor&) const = 0;
+
+ virtual MethodId amqpMethodId() const = 0;
+ virtual ClassId amqpClassId() const = 0;
+ virtual bool isContentBearing() const = 0;
+ virtual bool resultExpected() const = 0;
+ virtual bool responseExpected() const = 0;
+
+ template <class T> bool isA() const {
+ return amqpClassId()==T::CLASS_ID && amqpMethodId()==T::METHOD_ID;
+ }
+
+ virtual uint32_t encodedSize() const = 0;
+ virtual uint8_t type() const { return METHOD_BODY; }
+
+ virtual bool isSync() const { return false; /*only ModelMethods can have the sync flag set*/ }
+ virtual void setSync(bool) const { /*only ModelMethods can have the sync flag set*/ }
+
+ AMQMethodBody* getMethod() { return this; }
+ const AMQMethodBody* getMethod() const { return this; }
+ void accept(AMQBodyConstVisitor& v) const { v.visit(*this); }
+};
+
+
+}} // namespace qpid::framing
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/framing/AMQP_HighestVersion.h b/RC9/qpid/cpp/src/qpid/framing/AMQP_HighestVersion.h
new file mode 100644
index 0000000000..42139c7937
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/AMQP_HighestVersion.h
@@ -0,0 +1,40 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/*
+ * This file used to be auto-generated by Qpid Gentools v.0.1
+ * its here temporarily until we get a full solution to multi-version support
+ */
+#ifndef qpid_framing_highestProtocolVersion__
+#define qpid_framing_highestProtocolVersion__
+
+#include "qpid/framing/ProtocolVersion.h"
+
+
+namespace qpid {
+namespace framing {
+
+static ProtocolVersion highestProtocolVersion(0, 10);
+
+} /* namespace framing */
+} /* namespace qpid */
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/framing/AccumulatedAck.cpp b/RC9/qpid/cpp/src/qpid/framing/AccumulatedAck.cpp
new file mode 100644
index 0000000000..2d3ecf3f6a
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/AccumulatedAck.cpp
@@ -0,0 +1,164 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "AccumulatedAck.h"
+
+#include <assert.h>
+#include <iostream>
+#include <boost/bind.hpp>
+
+using std::list;
+using std::max;
+using std::min;
+using namespace qpid::framing;
+
+AccumulatedAck::AccumulatedAck(SequenceNumber r) : mark(r) {}
+
+void AccumulatedAck::update(SequenceNumber first, SequenceNumber last){
+ assert(first <= last);
+ if (last < mark) return;
+
+
+ Range r(first, last);
+ bool handled = false;
+ bool markMerged = false;
+ list<Range>::iterator merged = ranges.end();
+ if (r.mergeable(mark)) {
+ mark = r.end;
+ markMerged = true;
+ handled = true;
+ } else {
+ for (list<Range>::iterator i = ranges.begin(); i != ranges.end() && !handled; i++) {
+ if (i->merge(r)) {
+ merged = i;
+ handled = true;
+ } else if (r.start < i->start) {
+ ranges.insert(i, r);
+ handled = true;
+ }
+ }
+ }
+ if (!handled) {
+ ranges.push_back(r);
+ } else {
+ while (!ranges.empty() && ranges.front().end <= mark) {
+ ranges.pop_front();
+ }
+ if (markMerged) {
+ //new range is incorporated, but may be possible to consolidate
+ merged = ranges.begin();
+ while (merged != ranges.end() && merged->mergeable(mark)) {
+ mark = merged->end;
+ merged = ranges.erase(merged);
+ }
+ }
+ if (merged != ranges.end()) {
+ //consolidate ranges
+ list<Range>::iterator i = merged;
+ list<Range>::iterator j = i++;
+ while (i != ranges.end() && j->merge(*i)) {
+ j = i++;
+ }
+ }
+ }
+}
+
+void AccumulatedAck::consolidate(){}
+
+void AccumulatedAck::clear(){
+ mark = SequenceNumber(0);//not sure that this is valid when wraparound is a possibility
+ ranges.clear();
+}
+
+bool AccumulatedAck::covers(SequenceNumber tag) const{
+ if (tag <= mark) return true;
+ for (list<Range>::const_iterator i = ranges.begin(); i != ranges.end(); i++) {
+ if (i->contains(tag)) return true;
+ }
+ return false;
+}
+
+void AccumulatedAck::collectRanges(SequenceNumberSet& set) const
+{
+ for (list<Range>::const_iterator i = ranges.begin(); i != ranges.end(); i++) {
+ set.push_back(i->start);
+ set.push_back(i->end);
+ }
+}
+
+void AccumulatedAck::update(const SequenceNumber cumulative, const SequenceNumberSet& range)
+{
+ update(mark, cumulative);
+ range.processRanges(*this);
+}
+
+
+bool Range::contains(SequenceNumber i) const
+{
+ return i >= start && i <= end;
+}
+
+bool Range::intersect(const Range& r) const
+{
+ return r.contains(start) || r.contains(end) || contains(r.start) || contains(r.end);
+}
+
+bool Range::merge(const Range& r)
+{
+ if (intersect(r) || mergeable(r.end) || r.mergeable(end)) {
+ start = min(start, r.start);
+ end = max(end, r.end);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool Range::mergeable(const SequenceNumber& s) const
+{
+ if (contains(s) || start - s == 1) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+Range::Range(SequenceNumber s, SequenceNumber e) : start(s), end(e) {}
+
+
+namespace qpid{
+namespace framing{
+ std::ostream& operator<<(std::ostream& out, const Range& r)
+ {
+ out << "[" << r.start.getValue() << "-" << r.end.getValue() << "]";
+ return out;
+ }
+
+ std::ostream& operator<<(std::ostream& out, const AccumulatedAck& a)
+ {
+ out << "{mark: " << a.mark.getValue() << ", ranges: (";
+ for (list<Range>::const_iterator i = a.ranges.begin(); i != a.ranges.end(); i++) {
+ if (i != a.ranges.begin()) out << ", ";
+ out << *i;
+ }
+ out << ")]";
+ return out;
+ }
+}}
diff --git a/RC9/qpid/cpp/src/qpid/framing/AccumulatedAck.h b/RC9/qpid/cpp/src/qpid/framing/AccumulatedAck.h
new file mode 100644
index 0000000000..ea78b797e0
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/AccumulatedAck.h
@@ -0,0 +1,76 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _AccumulatedAck_
+#define _AccumulatedAck_
+
+#include <algorithm>
+#include <functional>
+#include <list>
+#include <ostream>
+#include "SequenceNumber.h"
+#include "SequenceNumberSet.h"
+
+namespace qpid {
+ namespace framing {
+
+ struct Range
+ {
+ SequenceNumber start;
+ SequenceNumber end;
+
+ Range(SequenceNumber s, SequenceNumber e);
+ bool contains(SequenceNumber i) const;
+ bool intersect(const Range& r) const;
+ bool merge(const Range& r);
+ bool mergeable(const SequenceNumber& r) const;
+ };
+ /**
+ * Keeps an accumulated record of acknowledged messages (by delivery
+ * tag).
+ */
+ class AccumulatedAck {
+ public:
+ /**
+ * Everything up to this value has been acknowledged.
+ */
+ SequenceNumber mark;
+ /**
+ * List of individually acknowledged messages greater than the
+ * 'mark'.
+ */
+ std::list<Range> ranges;
+
+ explicit AccumulatedAck(SequenceNumber r = SequenceNumber());
+ void update(SequenceNumber firstTag, SequenceNumber lastTag);
+ void consolidate();
+ void clear();
+ bool covers(SequenceNumber tag) const;
+ void collectRanges(SequenceNumberSet& set) const;
+ void update(const SequenceNumber cumulative, const SequenceNumberSet& range);
+ void operator()(SequenceNumber first, SequenceNumber last) { update(first, last); }
+ };
+ std::ostream& operator<<(std::ostream&, const Range&);
+ std::ostream& operator<<(std::ostream&, const AccumulatedAck&);
+ }
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/framing/Array.cpp b/RC9/qpid/cpp/src/qpid/framing/Array.cpp
new file mode 100644
index 0000000000..9f072f7b05
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/Array.cpp
@@ -0,0 +1,129 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "Array.h"
+#include "Buffer.h"
+#include "FieldValue.h"
+#include "qpid/Exception.h"
+#include "qpid/framing/reply_exceptions.h"
+#include <assert.h>
+
+namespace qpid {
+namespace framing {
+
+Array::Array() : type(TYPE_CODE_VOID) {}
+
+Array::Array(TypeCode t) : type(t) {}
+
+Array::Array(uint8_t t) : type(typeCode(t)) {}
+
+Array::Array(const std::vector<std::string>& in)
+{
+ type = TYPE_CODE_STR16;
+ for (std::vector<std::string>::const_iterator i = in.begin(); i != in.end(); ++i) {
+ ValuePtr value(new Str16Value(*i));
+ values.push_back(value);
+ }
+}
+
+uint32_t Array::encodedSize() const {
+ //note: size is only included when used as a 'top level' type
+ uint32_t len(4/*size*/ + 1/*type*/ + 4/*count*/);
+ for(ValueVector::const_iterator i = values.begin(); i != values.end(); ++i) {
+ len += (*i)->getData().encodedSize();
+ }
+ return len;
+}
+
+int Array::count() const {
+ return values.size();
+}
+
+std::ostream& operator<<(std::ostream& out, const Array& a) {
+ out << typeName(a.getType()) << "{";
+ for(Array::ValueVector::const_iterator i = a.values.begin(); i != a.values.end(); ++i) {
+ if (i != a.values.begin()) out << ", ";
+ (*i)->print(out);
+ }
+ return out << "}";
+}
+
+void Array::encode(Buffer& buffer) const{
+ buffer.putLong(encodedSize() - 4);//size added only when array is a top-level type
+ buffer.putOctet(type);
+ buffer.putLong(count());
+ for (ValueVector::const_iterator i = values.begin(); i!=values.end(); ++i) {
+ (*i)->getData().encode(buffer);
+ }
+}
+
+void Array::decode(Buffer& buffer){
+ uint32_t size = buffer.getLong();//size added only when array is a top-level type
+ uint32_t available = buffer.available();
+ if (available < size) {
+ throw IllegalArgumentException(QPID_MSG("Not enough data for array, expected "
+ << size << " bytes but only " << available << " available"));
+ }
+ if (size) {
+ type = TypeCode(buffer.getOctet());
+ uint32_t count = buffer.getLong();
+
+ FieldValue dummy;
+ dummy.setType(type);
+ available = buffer.available();
+ if (available < count * dummy.getData().encodedSize()) {
+ throw IllegalArgumentException(QPID_MSG("Not enough data for array, expected "
+ << count << " items of " << dummy.getData().encodedSize()
+ << " bytes each but only " << available << " bytes available"));
+ }
+
+ for (uint32_t i = 0; i < count; i++) {
+ ValuePtr value(new FieldValue);
+ value->setType(type);
+ value->getData().decode(buffer);
+ values.push_back(ValuePtr(value));
+ }
+ }
+}
+
+
+bool Array::operator==(const Array& x) const {
+ if (type != x.type) return false;
+ if (values.size() != x.values.size()) return false;
+
+ for (ValueVector::const_iterator i = values.begin(), j = x.values.begin(); i != values.end(); ++i, ++j) {
+ if (*(i->get()) != *(j->get())) return false;
+ }
+
+ return true;
+}
+
+void Array::insert(iterator i, ValuePtr value) {
+ if (type != value->getType()) {
+ // FIXME aconway 2008-10-31: put meaningful strings in this message.
+ throw Exception(QPID_MSG("Wrong type of value in Array, expected " << type
+ << " but found " << TypeCode(value->getType())));
+ }
+ values.insert(i, value);
+}
+
+
+}
+}
diff --git a/RC9/qpid/cpp/src/qpid/framing/Array.h b/RC9/qpid/cpp/src/qpid/framing/Array.h
new file mode 100644
index 0000000000..183fcb6d5c
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/Array.h
@@ -0,0 +1,96 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "amqp_types.h"
+#include "FieldValue.h"
+#include "qpid/framing/TypeCode.h"
+#include <boost/shared_ptr.hpp>
+#include <iostream>
+#include <vector>
+
+#ifndef _Array_
+#define _Array_
+
+namespace qpid {
+namespace framing {
+
+class Buffer;
+
+class Array
+{
+ public:
+ typedef boost::shared_ptr<FieldValue> ValuePtr;
+ typedef std::vector<ValuePtr> ValueVector;
+ typedef ValueVector::const_iterator const_iterator;
+ typedef ValueVector::iterator iterator;
+
+ uint32_t encodedSize() const;
+ void encode(Buffer& buffer) const;
+ void decode(Buffer& buffer);
+
+ int count() const;
+ bool operator==(const Array& other) const;
+
+ Array();
+ Array(TypeCode type);
+ Array(uint8_t type);
+ //creates a longstr array
+ Array(const std::vector<std::string>& in);
+
+ TypeCode getType() const { return type; }
+
+ // std collection interface.
+ const_iterator begin() const { return values.begin(); }
+ const_iterator end() const { return values.end(); }
+ iterator begin() { return values.begin(); }
+ iterator end(){ return values.end(); }
+
+ ValuePtr front() const { return values.front(); }
+ ValuePtr back() const { return values.back(); }
+ size_t size() const { return values.size(); }
+
+ void insert(iterator i, ValuePtr value);
+ void erase(iterator i) { values.erase(i); }
+ void push_back(ValuePtr value) { values.insert(end(), value); }
+ void pop_back() { values.pop_back(); }
+
+ // Non-std interface
+ void add(ValuePtr value) { push_back(value); }
+
+ template <class T>
+ void collect(std::vector<T>& out) const
+ {
+ for (ValueVector::const_iterator i = values.begin(); i != values.end(); ++i) {
+ out.push_back((*i)->get<T>());
+ }
+ }
+
+ private:
+ TypeCode type;
+ ValueVector values;
+
+ friend std::ostream& operator<<(std::ostream& out, const Array& body);
+};
+
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/framing/Blob.cpp b/RC9/qpid/cpp/src/qpid/framing/Blob.cpp
new file mode 100644
index 0000000000..388d4b64ef
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/Blob.cpp
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Blob.h"
+
+
+namespace qpid {
+namespace framing {
+
+void BlobHelper<void>::destroy(void*) {}
+
+void BlobHelper<void>::copy(void*, const void*) {}
+
+}} // namespace qpid::framing
diff --git a/RC9/qpid/cpp/src/qpid/framing/Blob.h b/RC9/qpid/cpp/src/qpid/framing/Blob.h
new file mode 100644
index 0000000000..5c84384ad7
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/Blob.h
@@ -0,0 +1,197 @@
+#ifndef QPID_FRAMING_BLOB_H
+#define QPID_FRAMING_BLOB_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <boost/static_assert.hpp>
+#include <boost/aligned_storage.hpp>
+#include <boost/checked_delete.hpp>
+#include <boost/utility/typed_in_place_factory.hpp>
+#include <boost/type_traits/is_base_and_derived.hpp>
+#include <boost/utility/enable_if.hpp>
+#include <boost/version.hpp>
+
+#include <new>
+
+#include <assert.h>
+
+
+namespace qpid {
+namespace framing {
+
+using boost::in_place;
+using boost::typed_in_place_factory_base;
+
+/** 0-arg typed_in_place_factory, missing in pre-1.35 boost. */
+#if (BOOST_VERSION < 103500)
+template <class T>
+struct typed_in_place_factory0 : public typed_in_place_factory_base {
+ typedef T value_type ;
+ void apply ( void* address ) const { new (address) T(); }
+};
+
+/** 0-arg in_place<T>() function, missing from boost. */
+template<class T>
+typed_in_place_factory0<T> in_place() { return typed_in_place_factory0<T>(); }
+#endif
+
+template <class T, class R=void>
+struct EnableInPlace
+ : public boost::enable_if<boost::is_base_and_derived<
+ typed_in_place_factory_base, T>,
+ R>
+{};
+
+template <class T, class R=void>
+struct DisableInPlace
+ : public boost::disable_if<boost::is_base_and_derived<
+ typed_in_place_factory_base, T>,
+ R>
+{};
+
+template <class T> struct BlobHelper {
+ static void destroy(void* ptr) { static_cast<T*>(ptr)->~T(); }
+ static void copy(void* dest, const void* src) {
+ new (dest) T(*static_cast<const T*>(src));
+ }
+};
+
+template <> struct BlobHelper<void> {
+ static void destroy(void*);
+ static void copy(void* to, const void* from);
+};
+
+/**
+ * A Blob is a chunk of memory which can contain a single object at
+ * a time-arbitrary type, provided sizeof(T)<=blob.size(). Using Blobs
+ * ensures proper construction and destruction of its contents,
+ * and proper copying between Blobs, but nothing else.
+ *
+ * In particular you must ensure that the Blob is big enough for its
+ * contents and must know the type of object in the Blob to cast get().
+ *
+ * If BaseType is specified then only an object that can be
+ * static_cast to BaseType may be stored in the Blob.
+ */
+template <size_t Size, class BaseType=void>
+class Blob
+{
+ boost::aligned_storage<Size> store;
+ BaseType* basePtr;
+
+ void (*destroy)(void*);
+ void (*copy)(void*, const void*);
+
+ template <class T>void setType() {
+ BOOST_STATIC_ASSERT(sizeof(T) <= Size);
+ destroy=&BlobHelper<T>::destroy;
+ copy=&BlobHelper<T>::copy;
+ // Base pointer may be offeset from store.address()
+ basePtr = reinterpret_cast<T*>(store.address());
+ }
+
+ void initialize() {
+ destroy=&BlobHelper<void>::destroy;
+ copy=&BlobHelper<void>::copy;
+ basePtr=0;
+ }
+
+ template<class Factory>
+ typename EnableInPlace<Factory>::type apply(const Factory& factory)
+ {
+ typedef typename Factory::value_type T;
+ assert(empty());
+ factory.apply(store.address());
+ setType<T>();
+ }
+
+ void assign(const Blob& b) {
+ assert(empty());
+ if (b.empty()) return;
+ b.copy(this->store.address(), b.store.address());
+ copy = b.copy;
+ destroy = b.destroy;
+ basePtr = reinterpret_cast<BaseType*>(
+ ((char*)this)+ ((const char*)(b.basePtr) - (const char*)(&b)));
+ }
+
+ public:
+ /** Construct an empty Blob. */
+ Blob() { initialize(); }
+
+ /** Copy a Blob. */
+ Blob(const Blob& b) { initialize(); assign(b); }
+
+ /** Construct from in_place constructor. */
+ template<class InPlace>
+ Blob(const InPlace & expr, typename EnableInPlace<InPlace>::type* =0) {
+ initialize(); apply(expr);
+ }
+
+ /** Construct by copying an object constructor. */
+ template<class T>
+ Blob(const T & t, typename DisableInPlace<T>::type* =0) {
+ initialize(); apply(in_place<T>(t));
+ }
+
+ ~Blob() { clear(); }
+
+ /** Assign from another Blob. */
+ Blob& operator=(const Blob& b) {
+ clear();
+ assign(b);
+ return *this;
+ }
+
+ /** Assign from an in_place constructor expression. */
+ template<class InPlace>
+ typename EnableInPlace<InPlace,Blob&>::type operator=(const InPlace& expr) {
+ clear(); apply(expr); return *this;
+ }
+
+ /** Assign from an object of type T. */
+ template <class T>
+ typename DisableInPlace<T, Blob&>::type operator=(const T& x) {
+ clear(); apply(in_place<T>(x)); return *this;
+ }
+
+ /** Get pointer to Blob contents, returns 0 if empty. */
+ BaseType* get() { return basePtr; }
+
+ /** Get pointer to Blob contents, returns 0 if empty. */
+ const BaseType* get() const { return basePtr; }
+
+ /** Destroy the object in the Blob making it empty. */
+ void clear() {
+ void (*oldDestroy)(void*) = destroy;
+ initialize();
+ oldDestroy(store.address());
+ }
+
+ bool empty() const { return destroy==BlobHelper<void>::destroy; }
+
+ static size_t size() { return Size; }
+};
+
+}} // namespace qpid::framing
+
+
+#endif /*!QPID_FRAMING_BLOB_H*/
diff --git a/RC9/qpid/cpp/src/qpid/framing/BodyHandler.cpp b/RC9/qpid/cpp/src/qpid/framing/BodyHandler.cpp
new file mode 100644
index 0000000000..ffbcf33a95
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/BodyHandler.cpp
@@ -0,0 +1,55 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "BodyHandler.h"
+#include "AMQMethodBody.h"
+#include "AMQHeaderBody.h"
+#include "AMQContentBody.h"
+#include "AMQHeartbeatBody.h"
+#include <boost/cast.hpp>
+#include "qpid/framing/reply_exceptions.h"
+
+using namespace qpid::framing;
+using namespace boost;
+
+BodyHandler::~BodyHandler() {}
+
+// TODO aconway 2007-08-13: Replace with visitor.
+void BodyHandler::handleBody(AMQBody* body) {
+ switch(body->type())
+ {
+ case METHOD_BODY:
+ handleMethod(polymorphic_downcast<AMQMethodBody*>(body));
+ break;
+ case HEADER_BODY:
+ handleHeader(polymorphic_downcast<AMQHeaderBody*>(body));
+ break;
+ case CONTENT_BODY:
+ handleContent(polymorphic_downcast<AMQContentBody*>(body));
+ break;
+ case HEARTBEAT_BODY:
+ handleHeartbeat(polymorphic_downcast<AMQHeartbeatBody*>(body));
+ break;
+ default:
+ throw FramingErrorException(
+ QPID_MSG("Invalid frame type " << body->type()));
+ }
+}
+
diff --git a/RC9/qpid/cpp/src/qpid/framing/BodyHandler.h b/RC9/qpid/cpp/src/qpid/framing/BodyHandler.h
new file mode 100644
index 0000000000..9ded737195
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/BodyHandler.h
@@ -0,0 +1,56 @@
+#ifndef _BodyHandler_
+#define _BodyHandler_
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <boost/shared_ptr.hpp>
+
+namespace qpid {
+namespace framing {
+class AMQBody;
+class AMQMethodBody;
+class AMQHeaderBody;
+class AMQContentBody;
+class AMQHeartbeatBody;
+
+// TODO aconway 2007-08-10: rework using Visitor pattern?
+
+/**
+ * Interface to handle incoming frame bodies.
+ * Derived classes provide logic for each frame type.
+ */
+class BodyHandler {
+ public:
+ virtual ~BodyHandler();
+ virtual void handleBody(AMQBody* body);
+
+ protected:
+ virtual void handleMethod(AMQMethodBody*) = 0;
+ virtual void handleHeader(AMQHeaderBody*) = 0;
+ virtual void handleContent(AMQContentBody*) = 0;
+ virtual void handleHeartbeat(AMQHeartbeatBody*) = 0;
+};
+
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/framing/BodyHolder.cpp b/RC9/qpid/cpp/src/qpid/framing/BodyHolder.cpp
new file mode 100644
index 0000000000..b30a52a38e
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/BodyHolder.cpp
@@ -0,0 +1,76 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "BodyHolder.h"
+#include "AMQMethodBody.h"
+#include "AMQHeaderBody.h"
+#include "AMQContentBody.h"
+#include "AMQHeartbeatBody.h"
+#include "Buffer.h"
+#include "qpid/framing/reply_exceptions.h"
+
+namespace qpid {
+namespace framing {
+
+
+// BodyHolder::operator=(const AMQBody&) is defined
+// in generated file BodyHolder_gen.cpp
+
+
+void BodyHolder::encode(Buffer& b) const {
+ const AMQMethodBody* method=getMethod();
+ if (method) {
+ b.putOctet(method->amqpClassId());
+ b.putOctet(method->amqpMethodId());
+ method->encode(b);
+ }
+ else
+ get()->encode(b);
+}
+
+void BodyHolder::decode(uint8_t type, Buffer& buffer, uint32_t size) {
+ switch(type)
+ {
+ case 0://CONTROL
+ case METHOD_BODY: {
+ ClassId c = buffer.getOctet();
+ MethodId m = buffer.getOctet();
+ setMethod(c, m);
+ break;
+ }
+ case HEADER_BODY: *this=in_place<AMQHeaderBody>(); break;
+ case CONTENT_BODY: *this=in_place<AMQContentBody>(); break;
+ case HEARTBEAT_BODY: *this=in_place<AMQHeartbeatBody>(); break;
+ default:
+ throw IllegalArgumentException(QPID_MSG("Invalid frame type " << type));
+ }
+ get()->decode(buffer, size);
+}
+
+uint32_t BodyHolder::encodedSize() const {
+ const AMQMethodBody* method=getMethod();
+ if (method)
+ return sizeof(ClassId)+sizeof(MethodId)+method->encodedSize();
+ else
+ return get()->encodedSize();
+}
+
+}} // namespace qpid::framing
+
diff --git a/RC9/qpid/cpp/src/qpid/framing/BodyHolder.h b/RC9/qpid/cpp/src/qpid/framing/BodyHolder.h
new file mode 100644
index 0000000000..0a35bb5e99
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/BodyHolder.h
@@ -0,0 +1,88 @@
+#ifndef QPID_FRAMING_BODYHOLDER_H
+#define QPID_FRAMING_BODYHOLDER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/framing/AMQBody.h"
+#include "qpid/framing/Blob.h"
+#include "qpid/framing/MaxMethodBodySize.h" // Generated file.
+#include "qpid/framing/amqp_types.h"
+#include "qpid/RefCounted.h"
+
+
+namespace qpid {
+namespace framing {
+
+class AMQMethodBody;
+class AMQBody;
+class Buffer;
+
+/**
+ * Holder for arbitrary frame body.
+ */
+class BodyHolder : public RefCounted
+{
+ public:
+ // default copy, assign dtor ok.
+ BodyHolder() {}
+ BodyHolder(const AMQBody& b) { setBody(b); }
+ BodyHolder(ClassId c, MethodId m) { setMethod(c,m); }
+
+ /** Construct from an in_place constructor expression. */
+ template <class InPlace>
+ BodyHolder(const InPlace& ip, typename EnableInPlace<InPlace>::type* =0)
+ : blob(ip) {}
+
+ void setBody(const AMQBody& b);
+
+ /** Assign from an in_place constructor expression. */
+ template <class InPlace>
+ typename EnableInPlace<InPlace,BodyHolder&>::type
+ operator=(const InPlace& ip) { blob=ip; return *this; }
+
+ /** Assign by copying. */
+ template <class T>
+ typename DisableInPlace<T,BodyHolder&>::type operator=(const T& x)
+ { blob=in_place<T>(x); return *this; }
+
+ /** Set to method with ClassId c, MethodId m. */
+ void setMethod(ClassId c, MethodId m);
+
+ void encode(Buffer&) const;
+ void decode(uint8_t frameType, Buffer&, uint32_t=0);
+ uint32_t encodedSize() const;
+
+ /** Return body pointer or 0 if empty. */
+ AMQBody* get() { return blob.get(); }
+ const AMQBody* get() const { return blob.get(); }
+
+ /** Return method pointer or 0 if not a method. */
+ AMQMethodBody* getMethod() { return get()->getMethod(); }
+ const AMQMethodBody* getMethod() const { return get()->getMethod(); }
+
+ private:
+ Blob<MAX_METHOD_BODY_SIZE, AMQBody> blob;
+};
+
+}} // namespace qpid::framing
+
+#endif /*!QPID_FRAMING_BODYHOLDER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/framing/Buffer.cpp b/RC9/qpid/cpp/src/qpid/framing/Buffer.cpp
new file mode 100644
index 0000000000..a90c3a2e64
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/Buffer.cpp
@@ -0,0 +1,319 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "Buffer.h"
+#include "FieldTable.h"
+#include <string.h>
+#include <boost/format.hpp>
+namespace qpid {
+
+namespace framing {
+
+Buffer::Buffer(char* _data, uint32_t _size)
+ : size(_size), data(_data), position(0) {
+}
+
+void Buffer::record(){
+ r_position = position;
+}
+
+void Buffer::restore(bool reRecord){
+ uint32_t savedPosition = position;
+
+ position = r_position;
+
+ if (reRecord)
+ r_position = savedPosition;
+}
+
+void Buffer::reset(){
+ position = 0;
+}
+
+///////////////////////////////////////////////////
+
+void Buffer::putOctet(uint8_t i){
+ data[position++] = i;
+ assert(position <= size);
+}
+
+void Buffer::putShort(uint16_t i){
+ uint16_t b = i;
+ data[position++] = (uint8_t) (0xFF & (b >> 8));
+ data[position++] = (uint8_t) (0xFF & b);
+ assert(position <= size);
+}
+
+void Buffer::putLong(uint32_t i){
+ uint32_t b = i;
+ data[position++] = (uint8_t) (0xFF & (b >> 24));
+ data[position++] = (uint8_t) (0xFF & (b >> 16));
+ data[position++] = (uint8_t) (0xFF & (b >> 8));
+ data[position++] = (uint8_t) (0xFF & b);
+ assert(position <= size);
+}
+
+void Buffer::putLongLong(uint64_t i){
+ uint32_t hi = i >> 32;
+ uint32_t lo = i;
+ putLong(hi);
+ putLong(lo);
+}
+
+void Buffer::putInt8(int8_t i){
+ data[position++] = (uint8_t) i;
+ assert(position <= size);
+}
+
+void Buffer::putInt16(int16_t i){
+ putShort((uint16_t) i);
+}
+
+void Buffer::putInt32(int32_t i){
+ putLong((uint32_t) i);
+}
+
+void Buffer::putInt64(int64_t i){
+ putLongLong((uint64_t) i);
+}
+
+void Buffer::putFloat(float f){
+ union {
+ uint32_t i;
+ float f;
+ } val;
+
+ val.f = f;
+ putLong (val.i);
+}
+
+void Buffer::putDouble(double f){
+ union {
+ uint64_t i;
+ double f;
+ } val;
+
+ val.f = f;
+ putLongLong (val.i);
+}
+
+void Buffer::putBin128(uint8_t* b){
+ memcpy (data + position, b, 16);
+ position += 16;
+}
+
+uint8_t Buffer::getOctet(){
+ uint8_t octet = static_cast<uint8_t>(data[position++]);
+ assert(position <= size);
+ return octet;
+}
+
+uint16_t Buffer::getShort(){
+ uint16_t hi = (unsigned char) data[position++];
+ hi = hi << 8;
+ hi |= (unsigned char) data[position++];
+ assert(position <= size);
+ return hi;
+}
+
+uint32_t Buffer::getLong(){
+ uint32_t a = (unsigned char) data[position++];
+ uint32_t b = (unsigned char) data[position++];
+ uint32_t c = (unsigned char) data[position++];
+ uint32_t d = (unsigned char) data[position++];
+ assert(position <= size);
+ a = a << 24;
+ a |= b << 16;
+ a |= c << 8;
+ a |= d;
+ return a;
+}
+
+uint64_t Buffer::getLongLong(){
+ uint64_t hi = getLong();
+ uint64_t lo = getLong();
+ hi = hi << 32;
+ return hi | lo;
+}
+
+int8_t Buffer::getInt8(){
+ int8_t i = static_cast<int8_t>(data[position++]);
+ assert(position <= size);
+ return i;
+}
+
+int16_t Buffer::getInt16(){
+ return (int16_t) getShort();
+}
+
+int32_t Buffer::getInt32(){
+ return (int32_t) getLong();
+}
+
+int64_t Buffer::getInt64(){
+ return (int64_t) getLongLong();
+}
+
+float Buffer::getFloat(){
+ union {
+ uint32_t i;
+ float f;
+ } val;
+ val.i = getLong();
+ return val.f;
+}
+
+double Buffer::getDouble(){
+ union {
+ uint64_t i;
+ double f;
+ } val;
+ val.i = getLongLong();
+ return val.f;
+}
+
+template <>
+uint64_t Buffer::getUInt<1>() {
+ return getOctet();
+}
+
+template <>
+uint64_t Buffer::getUInt<2>() {
+ return getShort();
+}
+
+template <>
+uint64_t Buffer::getUInt<4>() {
+ return getLong();
+}
+
+template <>
+uint64_t Buffer::getUInt<8>() {
+ return getLongLong();
+}
+
+template <>
+void Buffer::putUInt<1>(uint64_t i) {
+ putOctet(i);
+}
+
+template <>
+void Buffer::putUInt<2>(uint64_t i) {
+ putShort(i);
+}
+
+template <>
+void Buffer::putUInt<4>(uint64_t i) {
+ putLong(i);
+}
+
+template <>
+void Buffer::putUInt<8>(uint64_t i) {
+ putLongLong(i);
+}
+
+void Buffer::putShortString(const string& s){
+ size_t slen = s.length();
+ uint8_t len = slen < 0x100 ? (uint8_t) slen : 0xFF;
+ putOctet(len);
+ s.copy(data + position, len);
+ position += len;
+}
+
+void Buffer::putMediumString(const string& s){
+ size_t slen = s.length();
+ uint16_t len = slen < 0x10000 ? (uint16_t) slen : 0xFFFF;
+ putShort(len);
+ s.copy(data + position, len);
+ position += len;
+}
+
+void Buffer::putLongString(const string& s){
+ uint32_t len = s.length();
+ putLong(len);
+ s.copy(data + position, len);
+ position += len;
+}
+
+void Buffer::getShortString(string& s){
+ uint8_t len = getOctet();
+ checkAvailable(len);
+ s.assign(data + position, len);
+ position += len;
+}
+
+void Buffer::getMediumString(string& s){
+ uint16_t len = getShort();
+ checkAvailable(len);
+ s.assign(data + position, len);
+ position += len;
+}
+
+void Buffer::getLongString(string& s){
+ uint32_t len = getLong();
+ checkAvailable(len);
+ s.assign(data + position, len);
+ position += len;
+}
+
+void Buffer::getBin128(uint8_t* b){
+ memcpy (b, data + position, 16);
+ position += 16;
+}
+
+void Buffer::putRawData(const string& s){
+ uint32_t len = s.length();
+ s.copy(data + position, len);
+ position += len;
+}
+
+void Buffer::getRawData(string& s, uint32_t len){
+ checkAvailable(len);
+ s.assign(data + position, len);
+ position += len;
+}
+
+void Buffer::putRawData(const uint8_t* s, size_t len){
+ memcpy(data + position, s, len);
+ position += len;
+}
+
+void Buffer::getRawData(uint8_t* s, size_t len){
+ checkAvailable(len);
+ memcpy(s, data + position, len);
+ position += len;
+}
+
+void Buffer::dump(std::ostream& out) const {
+ for (uint32_t i = position; i < size; i++)
+ {
+ if (i != position)
+ out << " ";
+ out << boost::format("%02x") % ((unsigned) (uint8_t) data[i]);
+ }
+}
+
+std::ostream& operator<<(std::ostream& out, const Buffer& b){
+ out << "Buffer[";
+ b.dump(out);
+ return out << "]";
+}
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/framing/Buffer.h b/RC9/qpid/cpp/src/qpid/framing/Buffer.h
new file mode 100644
index 0000000000..828e6e963a
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/Buffer.h
@@ -0,0 +1,135 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "amqp_types.h"
+#include "qpid/Exception.h"
+#include <boost/iterator/iterator_facade.hpp>
+
+#ifndef _Buffer_
+#define _Buffer_
+
+namespace qpid {
+namespace framing {
+
+struct OutOfBounds : qpid::Exception {
+ OutOfBounds() : qpid::Exception(std::string("Out of Bounds")) {}
+};
+
+class Content;
+class FieldTable;
+
+class Buffer
+{
+ uint32_t size;
+ char* data;
+ uint32_t position;
+ uint32_t r_position;
+
+ void checkAvailable(uint32_t count) { if (position + count > size) throw OutOfBounds(); }
+
+ public:
+
+ /** Buffer input/output iterator.
+ * Supports using an amqp_0_10::Codec with a framing::Buffer.
+ */
+ class Iterator : public boost::iterator_facade<
+ Iterator, char, boost::random_access_traversal_tag>
+ {
+ public:
+ Iterator(Buffer& b) : buffer(&b) {}
+
+ private:
+ friend class boost::iterator_core_access;
+ char& dereference() const { return buffer->data[buffer->position]; }
+ void increment() { ++buffer->position; }
+ bool equal(const Iterator& x) const { return buffer == x.buffer; }
+
+ Buffer* buffer;
+ };
+
+ friend class Iterator;
+
+ Buffer(char* data=0, uint32_t size=0);
+
+ void record();
+ void restore(bool reRecord = false);
+ void reset();
+
+ uint32_t available() { return size - position; }
+ uint32_t getSize() { return size; }
+ uint32_t getPosition() { return position; }
+ Iterator getIterator() { return Iterator(*this); }
+ char* getPointer() { return data; }
+
+ void putOctet(uint8_t i);
+ void putShort(uint16_t i);
+ void putLong(uint32_t i);
+ void putLongLong(uint64_t i);
+ void putInt8(int8_t i);
+ void putInt16(int16_t i);
+ void putInt32(int32_t i);
+ void putInt64(int64_t i);
+ void putFloat(float f);
+ void putDouble(double f);
+ void putBin128(uint8_t* b);
+
+ uint8_t getOctet();
+ uint16_t getShort();
+ uint32_t getLong();
+ uint64_t getLongLong();
+ int8_t getInt8();
+ int16_t getInt16();
+ int32_t getInt32();
+ int64_t getInt64();
+ float getFloat();
+ double getDouble();
+
+ template <int n>
+ uint64_t getUInt();
+
+ template <int n>
+ void putUInt(uint64_t);
+
+ void putShortString(const string& s);
+ void putMediumString(const string& s);
+ void putLongString(const string& s);
+ void getShortString(string& s);
+ void getMediumString(string& s);
+ void getLongString(string& s);
+ void getBin128(uint8_t* b);
+
+ void putRawData(const string& s);
+ void getRawData(string& s, uint32_t size);
+
+ void putRawData(const uint8_t* data, size_t size);
+ void getRawData(uint8_t* data, size_t size);
+
+ template <class T> void put(const T& data) { data.encode(*this); }
+ template <class T> void get(T& data) { data.decode(*this); }
+
+ void dump(std::ostream&) const;
+};
+
+std::ostream& operator<<(std::ostream&, const Buffer&);
+
+}} // namespace qpid::framing
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/framing/ChannelHandler.h b/RC9/qpid/cpp/src/qpid/framing/ChannelHandler.h
new file mode 100644
index 0000000000..69aaeac492
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/ChannelHandler.h
@@ -0,0 +1,53 @@
+#ifndef QPID_FRAMING_CHANNELHANDLER_H
+#define QPID_FRAMING_CHANNELHANDLER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "FrameHandler.h"
+#include "AMQFrame.h"
+
+namespace qpid {
+namespace framing {
+
+/**
+ * Sets the channel number on outgoing frames.
+ */
+class ChannelHandler : public FrameHandler
+{
+ public:
+ ChannelHandler(uint16_t channelId=0, FrameHandler* next=0)
+ : FrameHandler(next), channel(channelId) {}
+ void handle(AMQFrame& frame) {
+ frame.setChannel(channel);
+ next->handle(frame);
+ }
+ uint16_t get() const { return channel; }
+ ChannelHandler& set(uint16_t ch) { channel=ch; return *this; }
+ operator uint16_t() const { return get(); }
+ ChannelHandler& operator=(uint16_t ch) { return set(ch); }
+
+ private:
+ uint16_t channel;
+};
+
+}} // namespace qpid::framing
+
+#endif /*!QPID_FRAMING_CHANNELHANDLER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/framing/Endian.cpp b/RC9/qpid/cpp/src/qpid/framing/Endian.cpp
new file mode 100644
index 0000000000..1948579b88
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/Endian.cpp
@@ -0,0 +1,52 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "Endian.h"
+
+namespace qpid {
+namespace framing {
+
+Endian::Endian() : littleEndian(!testBigEndian()) {}
+
+bool Endian::testBigEndian()
+{
+ uint16_t a = 1;
+ uint16_t b;
+ uint8_t* p = (uint8_t*) &b;
+ p[0] = 0xFF & (a >> 8);
+ p[1] = 0xFF & (a);
+ return a == b;
+}
+
+uint8_t* Endian::convertIfRequired(uint8_t* const octets, int width)
+{
+ if (instance.littleEndian) {
+ for (int i = 0; i < (width/2); i++) {
+ uint8_t temp = octets[i];
+ octets[i] = octets[width - (1 + i)];
+ octets[width - (1 + i)] = temp;
+ }
+ }
+ return octets;
+}
+
+const Endian Endian::instance;
+
+}} // namespace qpid::framing
diff --git a/RC9/qpid/cpp/src/qpid/framing/Endian.h b/RC9/qpid/cpp/src/qpid/framing/Endian.h
new file mode 100644
index 0000000000..077d5a3e9b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/Endian.h
@@ -0,0 +1,46 @@
+#ifndef QPID_FRAMING_ENDIAN_H
+#define QPID_FRAMING_ENDIAN_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/IntegerTypes.h"
+
+namespace qpid {
+namespace framing {
+
+/**
+ * Conversion utility for little-endian platforms that need to convert
+ * to and from network ordered octet sequences
+ */
+class Endian
+{
+ public:
+ static uint8_t* convertIfRequired(uint8_t* const octets, int width);
+ private:
+ const bool littleEndian;
+ Endian();
+ static const Endian instance;
+ static bool testBigEndian();
+};
+}} // namespace qpid::framing
+
+#endif /*!QPID_FRAMING_ENDIAN_H*/
diff --git a/RC9/qpid/cpp/src/qpid/framing/FieldTable.cpp b/RC9/qpid/cpp/src/qpid/framing/FieldTable.cpp
new file mode 100644
index 0000000000..7260261970
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/FieldTable.cpp
@@ -0,0 +1,240 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "FieldTable.h"
+#include "Array.h"
+#include "Buffer.h"
+#include "Endian.h"
+#include "FieldValue.h"
+#include "qpid/Exception.h"
+#include "qpid/framing/reply_exceptions.h"
+#include <assert.h>
+
+namespace qpid {
+namespace framing {
+
+FieldTable::FieldTable(const FieldTable& ft)
+{
+ *this = ft;
+}
+
+FieldTable& FieldTable::operator=(const FieldTable& ft)
+{
+ clear();
+ values = ft.values;
+ return *this;
+}
+
+FieldTable::~FieldTable() {}
+
+uint32_t FieldTable::encodedSize() const {
+ uint32_t len(4/*size field*/ + 4/*count field*/);
+ for(ValueMap::const_iterator i = values.begin(); i != values.end(); ++i) {
+ // shortstr_len_byte + key size + value size
+ len += 1 + (i->first).size() + (i->second)->encodedSize();
+ }
+ return len;
+}
+
+int FieldTable::count() const {
+ return values.size();
+}
+
+namespace
+{
+std::ostream& operator<<(std::ostream& out, const FieldTable::ValueMap::value_type& i) {
+ return out << i.first << ":" << *i.second;
+}
+}
+
+std::ostream& operator<<(std::ostream& out, const FieldTable& t) {
+ out << "{";
+ FieldTable::ValueMap::const_iterator i = t.begin();
+ if (i != t.end()) out << *i++;
+ while (i != t.end())
+ {
+ out << "," << *i++;
+ }
+ return out << "}";
+}
+
+void FieldTable::set(const std::string& name, const ValuePtr& value){
+ values[name] = value;
+}
+
+void FieldTable::setString(const std::string& name, const std::string& value){
+ values[name] = ValuePtr(new Str16Value(value));
+}
+
+void FieldTable::setInt(const std::string& name, const int value){
+ values[name] = ValuePtr(new IntegerValue(value));
+}
+
+void FieldTable::setInt64(const std::string& name, const int64_t value){
+ values[name] = ValuePtr(new Integer64Value(value));
+}
+
+void FieldTable::setTimestamp(const std::string& name, const uint64_t value){
+ values[name] = ValuePtr(new TimeValue(value));
+}
+
+void FieldTable::setUInt64(const std::string& name, const uint64_t value){
+ values[name] = ValuePtr(new Unsigned64Value(value));
+}
+
+void FieldTable::setTable(const std::string& name, const FieldTable& value)
+{
+ values[name] = ValuePtr(new FieldTableValue(value));
+}
+void FieldTable::setArray(const std::string& name, const Array& value)
+{
+ values[name] = ValuePtr(new ArrayValue(value));
+}
+
+void FieldTable::setFloat(const std::string& name, const float value){
+ values[name] = ValuePtr(new FloatValue(value));
+}
+
+void FieldTable::setDouble(const std::string& name, double value){
+ values[name] = ValuePtr(new DoubleValue(value));
+}
+
+FieldTable::ValuePtr FieldTable::get(const std::string& name) const
+{
+ ValuePtr value;
+ ValueMap::const_iterator i = values.find(name);
+ if ( i!=values.end() )
+ value = i->second;
+ return value;
+}
+
+namespace {
+ template <class T> T default_value() { return T(); }
+ template <> int default_value<int>() { return 0; }
+ template <> uint64_t default_value<uint64_t>() { return 0; }
+}
+
+template <class T>
+T getValue(const FieldTable::ValuePtr value)
+{
+ if (!value || !value->convertsTo<T>())
+ return default_value<T>();
+
+ return value->get<T>();
+}
+
+std::string FieldTable::getAsString(const std::string& name) const {
+ return getValue<std::string>(get(name));
+}
+
+int FieldTable::getAsInt(const std::string& name) const {
+ return getValue<int>(get(name));
+}
+
+uint64_t FieldTable::getAsUInt64(const std::string& name) const {
+ return static_cast<uint64_t>( getValue<int64_t>(get(name)));
+}
+
+int64_t FieldTable::getAsInt64(const std::string& name) const {
+ return getValue<int64_t>(get(name));
+}
+
+bool FieldTable::getTable(const std::string& name, FieldTable& value) const {
+ return getEncodedValue<FieldTable>(get(name), value);
+}
+
+bool FieldTable::getArray(const std::string& name, Array& value) const {
+ return getEncodedValue<Array>(get(name), value);
+}
+
+template <class T, int width, uint8_t typecode>
+bool getRawFixedWidthValue(FieldTable::ValuePtr vptr, T& value)
+{
+ if (vptr && vptr->getType() == typecode) {
+ FixedWidthValue<width>* fwv = dynamic_cast< FixedWidthValue<width>* >(&vptr->getData());
+ if (fwv) {
+ uint8_t* const octets = Endian::convertIfRequired(fwv->rawOctets(), width);
+ uint8_t* const target = reinterpret_cast<uint8_t*>(&value);
+ for (uint i = 0; i < width; ++i) target[i] = octets[i];
+ return true;
+ }
+ }
+ return false;
+}
+
+bool FieldTable::getFloat(const std::string& name, float& value) const {
+ return getRawFixedWidthValue<float, 4, 0x23>(get(name), value);
+}
+
+bool FieldTable::getDouble(const std::string& name, double& value) const {
+ return getRawFixedWidthValue<double, 8, 0x33>(get(name), value);
+}
+
+//uint64_t FieldTable::getTimestamp(const std::string& name) const {
+// return getValue<uint64_t>(name);
+//}
+
+void FieldTable::encode(Buffer& buffer) const{
+ buffer.putLong(encodedSize() - 4);
+ buffer.putLong(values.size());
+ for (ValueMap::const_iterator i = values.begin(); i!=values.end(); ++i) {
+ buffer.putShortString(i->first);
+ i->second->encode(buffer);
+ }
+}
+
+void FieldTable::decode(Buffer& buffer){
+ uint32_t len = buffer.getLong();
+ if (len) {
+ uint32_t available = buffer.available();
+ if (available < len)
+ throw IllegalArgumentException(QPID_MSG("Not enough data for field table."));
+ uint32_t count = buffer.getLong();
+ uint32_t leftover = available - len;
+ while(buffer.available() > leftover && count--){
+ std::string name;
+ ValuePtr value(new FieldValue);
+
+ buffer.getShortString(name);
+ value->decode(buffer);
+ values[name] = ValuePtr(value);
+ }
+ }
+}
+
+
+bool FieldTable::operator==(const FieldTable& x) const {
+ if (values.size() != x.values.size()) return false;
+ for (ValueMap::const_iterator i = values.begin(); i != values.end(); ++i) {
+ ValueMap::const_iterator j = x.values.find(i->first);
+ if (j == x.values.end()) return false;
+ if (*(i->second) != *(j->second)) return false;
+ }
+ return true;
+}
+
+void FieldTable::erase(const std::string& name)
+{
+ if (values.find(name) != values.end())
+ values.erase(name);
+}
+
+}
+}
diff --git a/RC9/qpid/cpp/src/qpid/framing/FieldTable.h b/RC9/qpid/cpp/src/qpid/framing/FieldTable.h
new file mode 100644
index 0000000000..9e1214a28c
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/FieldTable.h
@@ -0,0 +1,120 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <iostream>
+#include <vector>
+#include <boost/shared_ptr.hpp>
+#include <map>
+#include "amqp_types.h"
+
+#ifndef _FieldTable_
+#define _FieldTable_
+
+namespace qpid {
+ /**
+ * The framing namespace contains classes that are used to create,
+ * send and receive the basic packets from which AMQP is built.
+ */
+namespace framing {
+
+class Array;
+class FieldValue;
+class Buffer;
+
+/**
+ * A set of name-value pairs. (See the AMQP spec for more details on
+ * AMQP field tables).
+ *
+ * \ingroup clientapi
+ */
+class FieldTable
+{
+ public:
+ typedef boost::shared_ptr<FieldValue> ValuePtr;
+ typedef std::map<std::string, ValuePtr> ValueMap;
+ typedef ValueMap::iterator iterator;
+
+ FieldTable() {};
+ FieldTable(const FieldTable& ft);
+ ~FieldTable();
+ FieldTable& operator=(const FieldTable& ft);
+ uint32_t encodedSize() const;
+ void encode(Buffer& buffer) const;
+ void decode(Buffer& buffer);
+
+ int count() const;
+ void set(const std::string& name, const ValuePtr& value);
+ ValuePtr get(const std::string& name) const;
+ bool isSet(const std::string& name) const { return get(name).get() != 0; }
+
+ void setString(const std::string& name, const std::string& value);
+ void setInt(const std::string& name, const int value);
+ void setInt64(const std::string& name, const int64_t value);
+ void setTimestamp(const std::string& name, const uint64_t value);
+ void setUInt64(const std::string& name, const uint64_t value);
+ void setTable(const std::string& name, const FieldTable& value);
+ void setArray(const std::string& name, const Array& value);
+ void setFloat(const std::string& name, const float value);
+ void setDouble(const std::string& name, const double value);
+ //void setDecimal(string& name, xxx& value);
+
+ int getAsInt(const std::string& name) const;
+ uint64_t getAsUInt64(const std::string& name) const;
+ int64_t getAsInt64(const std::string& name) const;
+ std::string getAsString(const std::string& name) const;
+
+ bool getTable(const std::string& name, FieldTable& value) const;
+ bool getArray(const std::string& name, Array& value) const;
+ bool getFloat(const std::string& name, float& value) const;
+ bool getDouble(const std::string& name, double& value) const;
+ //bool getTimestamp(const std::string& name, uint64_t& value) const;
+ //bool getDecimal(string& name, xxx& value);
+ void erase(const std::string& name);
+
+
+ bool operator==(const FieldTable& other) const;
+
+ // Map-like interface.
+ // TODO: may need to duplicate into versions that return mutable iterator
+ ValueMap::const_iterator begin() const { return values.begin(); }
+ ValueMap::const_iterator end() const { return values.end(); }
+ ValueMap::const_iterator find(const std::string& s) const { return values.find(s); }
+
+ std::pair <ValueMap::iterator, bool> insert(const ValueMap::value_type&);
+ void clear() { values.clear(); }
+
+ // ### Hack Alert
+
+ ValueMap::iterator getValues() { return values.begin(); }
+
+ private:
+ ValueMap values;
+
+ friend std::ostream& operator<<(std::ostream& out, const FieldTable& body);
+};
+
+//class FieldNotFoundException{};
+//class UnknownFieldName : public FieldNotFoundException{};
+//class IncorrectFieldType : public FieldNotFoundException{};
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/framing/FieldValue.cpp b/RC9/qpid/cpp/src/qpid/framing/FieldValue.cpp
new file mode 100644
index 0000000000..ecf469236d
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/FieldValue.cpp
@@ -0,0 +1,180 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "FieldValue.h"
+#include "Array.h"
+#include "Buffer.h"
+#include "Endian.h"
+#include "qpid/framing/reply_exceptions.h"
+
+namespace qpid {
+namespace framing {
+
+uint8_t FieldValue::getType()
+{
+ return typeOctet;
+}
+
+void FieldValue::setType(uint8_t type)
+{
+ typeOctet = type;
+ if (typeOctet == 0xA8) {
+ data.reset(new EncodedValue<FieldTable>());
+ } else if (typeOctet == 0xAA) {
+ data.reset(new EncodedValue<Array>());
+ } else {
+ uint8_t lenType = typeOctet >> 4;
+ switch(lenType){
+ case 0:
+ data.reset(new FixedWidthValue<1>());
+ break;
+ case 1:
+ data.reset(new FixedWidthValue<2>());
+ break;
+ case 2:
+ data.reset(new FixedWidthValue<4>());
+ break;
+ case 3:
+ data.reset(new FixedWidthValue<8>());
+ break;
+ case 4:
+ data.reset(new FixedWidthValue<16>());
+ break;
+ case 5:
+ data.reset(new FixedWidthValue<32>());
+ break;
+ case 6:
+ data.reset(new FixedWidthValue<64>());
+ break;
+ case 7:
+ data.reset(new FixedWidthValue<128>());
+ break;
+ case 8:
+ data.reset(new VariableWidthValue<1>());
+ break;
+ case 9:
+ data.reset(new VariableWidthValue<2>());
+ break;
+ case 0xA:
+ data.reset(new VariableWidthValue<4>());
+ break;
+ case 0xC:
+ data.reset(new FixedWidthValue<5>());
+ break;
+ case 0xD:
+ data.reset(new FixedWidthValue<9>());
+ break;
+ case 0xF:
+ data.reset(new FixedWidthValue<0>());
+ break;
+ default:
+ throw IllegalArgumentException(QPID_MSG("Unknown field table value type: " << (int)typeOctet));
+ }
+ }
+}
+
+void FieldValue::decode(Buffer& buffer)
+{
+ setType(buffer.getOctet());
+ data->decode(buffer);
+}
+
+void FieldValue::encode(Buffer& buffer)
+{
+ buffer.putOctet(typeOctet);
+ data->encode(buffer);
+}
+
+bool FieldValue::operator==(const FieldValue& v) const
+{
+ return
+ typeOctet == v.typeOctet &&
+ *data == *v.data;
+}
+
+Str8Value::Str8Value(const std::string& v) :
+ FieldValue(
+ TYPE_CODE_STR8,
+ new VariableWidthValue<1>(
+ reinterpret_cast<const uint8_t*>(v.data()),
+ reinterpret_cast<const uint8_t*>(v.data()+v.size())))
+{
+}
+
+Str16Value::Str16Value(const std::string& v) :
+ FieldValue(
+ 0x95,
+ new VariableWidthValue<2>(
+ reinterpret_cast<const uint8_t*>(v.data()),
+ reinterpret_cast<const uint8_t*>(v.data()+v.size())))
+{}
+
+Struct32Value::Struct32Value(const std::string& v) :
+ FieldValue(
+ 0xAB,
+ new VariableWidthValue<4>(
+ reinterpret_cast<const uint8_t*>(v.data()),
+ reinterpret_cast<const uint8_t*>(v.data()+v.size())))
+{}
+
+IntegerValue::IntegerValue(int v) :
+ FieldValue(0x21, new FixedWidthValue<4>(v))
+{}
+
+FloatValue::FloatValue(float v) :
+ FieldValue(0x23, new FixedWidthValue<4>(Endian::convertIfRequired(reinterpret_cast<uint8_t*>(&v), 4)))
+{}
+
+DoubleValue::DoubleValue(double v) :
+ FieldValue(0x33, new FixedWidthValue<8>(Endian::convertIfRequired(reinterpret_cast<uint8_t*>(&v), 8)))
+{}
+
+Integer64Value::Integer64Value(int64_t v) :
+ FieldValue(0x31, new FixedWidthValue<8>(v))
+{}
+
+Unsigned64Value::Unsigned64Value(uint64_t v) :
+ FieldValue(0x32, new FixedWidthValue<8>(v))
+{}
+
+
+TimeValue::TimeValue(uint64_t v) :
+ FieldValue(0x38, new FixedWidthValue<8>(v))
+{
+}
+
+FieldTableValue::FieldTableValue(const FieldTable& f) : FieldValue(0xa8, new EncodedValue<FieldTable>(f))
+{
+}
+
+ArrayValue::ArrayValue(const Array& a) : FieldValue(0xaa, new EncodedValue<Array>(a))
+{
+}
+
+void FieldValue::print(std::ostream& out) const {
+ data->print(out);
+ out << TypeCode(typeOctet) << '(';
+ if (data->convertsToString()) out << data->getString();
+ else if (data->convertsToInt()) out << data->getInt();
+ else data->print(out);
+ out << ')';
+}
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/framing/FieldValue.h b/RC9/qpid/cpp/src/qpid/framing/FieldValue.h
new file mode 100644
index 0000000000..29760619e5
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/FieldValue.h
@@ -0,0 +1,320 @@
+#ifndef _framing_FieldValue_h
+#define _framing_FieldValue_h
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/Exception.h"
+#include "amqp_types.h"
+#include "Buffer.h"
+#include "FieldTable.h"
+
+#include "assert.h"
+
+#include <iostream>
+#include <memory>
+#include <vector>
+
+namespace qpid {
+namespace framing {
+
+//class Array;
+/**
+ * Exception that is the base exception for all field table errors.
+ *
+ * \ingroup clientapi
+ */
+class FieldValueException : public qpid::Exception {};
+
+/**
+ * Exception thrown when we can't perform requested conversion
+ *
+ * \ingroup clientapi
+ */
+struct InvalidConversionException : public FieldValueException {
+ InvalidConversionException() {}
+};
+
+/**
+ * Value that can appear in an AMQP field table
+ *
+ * \ingroup clientapi
+ */
+class FieldValue {
+ public:
+ /*
+ * Abstract type for content of different types
+ */
+ class Data {
+ public:
+ virtual ~Data() {};
+ virtual uint32_t encodedSize() const = 0;
+ virtual void encode(Buffer& buffer) = 0;
+ virtual void decode(Buffer& buffer) = 0;
+ virtual bool operator==(const Data&) const = 0;
+
+ virtual bool convertsToInt() const { return false; }
+ virtual bool convertsToString() const { return false; }
+ virtual int64_t getInt() const { throw InvalidConversionException();}
+ virtual std::string getString() const { throw InvalidConversionException(); }
+
+ virtual void print(std::ostream& out) const = 0;
+ };
+
+ FieldValue(): data(0) {};
+ // Default assignment operator is fine
+ void setType(uint8_t type);
+ uint8_t getType();
+ Data& getData() { return *data; }
+ uint32_t encodedSize() const { return 1 + data->encodedSize(); };
+ bool empty() const { return data.get() == 0; }
+ void encode(Buffer& buffer);
+ void decode(Buffer& buffer);
+ bool operator==(const FieldValue&) const;
+ bool operator!=(const FieldValue& v) const { return !(*this == v); }
+
+ void print(std::ostream& out) const;
+
+ template <typename T> bool convertsTo() const { return false; }
+ template <typename T> T get() const { throw InvalidConversionException(); }
+
+ protected:
+ FieldValue(uint8_t t, Data* d): typeOctet(t), data(d) {}
+
+ private:
+ uint8_t typeOctet;
+ std::auto_ptr<Data> data;
+};
+
+template <>
+inline bool FieldValue::convertsTo<int>() const { return data->convertsToInt(); }
+
+template <>
+inline bool FieldValue::convertsTo<int64_t>() const { return data->convertsToInt(); }
+
+template <>
+inline bool FieldValue::convertsTo<std::string>() const { return data->convertsToString(); }
+
+template <>
+inline int FieldValue::get<int>() const { return data->getInt(); }
+
+template <>
+inline int64_t FieldValue::get<int64_t>() const { return data->getInt(); }
+
+template <>
+inline std::string FieldValue::get<std::string>() const { return data->getString(); }
+
+inline std::ostream& operator<<(std::ostream& out, const FieldValue& v) {
+ v.print(out);
+ return out;
+}
+
+template <int width>
+class FixedWidthValue : public FieldValue::Data {
+ uint8_t octets[width];
+
+ public:
+ FixedWidthValue() {}
+ FixedWidthValue(const uint8_t (&data)[width]) : octets(data) {}
+ FixedWidthValue(const uint8_t* const data)
+ {
+ for (int i = 0; i < width; i++) octets[i] = data[i];
+ }
+ FixedWidthValue(uint64_t v)
+ {
+ for (int i = width; i > 1; --i) {
+ octets[i-1] = (uint8_t) (0xFF & v); v >>= 8;
+ }
+ octets[0] = (uint8_t) (0xFF & v);
+ }
+ uint32_t encodedSize() const { return width; }
+ void encode(Buffer& buffer) { buffer.putRawData(octets, width); }
+ void decode(Buffer& buffer) { buffer.getRawData(octets, width); }
+ bool operator==(const Data& d) const {
+ const FixedWidthValue<width>* rhs = dynamic_cast< const FixedWidthValue<width>* >(&d);
+ if (rhs == 0) return false;
+ else return std::equal(&octets[0], &octets[width], &rhs->octets[0]);
+ }
+
+ bool convertsToInt() const { return true; }
+ int64_t getInt() const
+ {
+ int64_t v = 0;
+ for (int i = 0; i < width-1; ++i) {
+ v |= octets[i]; v <<= 8;
+ }
+ v |= octets[width-1];
+ return v;
+ }
+ uint8_t* rawOctets() { return octets; }
+
+ void print(std::ostream& o) const { o << "F" << width << ":"; };
+};
+
+template <>
+class FixedWidthValue<0> : public FieldValue::Data {
+ public:
+ // Implicit default constructor is fine
+ uint32_t encodedSize() const { return 0; }
+ void encode(Buffer&) {};
+ void decode(Buffer&) {};
+ bool operator==(const Data& d) const {
+ const FixedWidthValue<0>* rhs = dynamic_cast< const FixedWidthValue<0>* >(&d);
+ return rhs != 0;
+ }
+ void print(std::ostream& o) const { o << "F0"; };
+};
+
+template <int lenwidth>
+class VariableWidthValue : public FieldValue::Data {
+ std::vector<uint8_t> octets;
+
+ public:
+ VariableWidthValue() {}
+ VariableWidthValue(const std::vector<uint8_t>& data) : octets(data) {}
+ VariableWidthValue(const uint8_t* start, const uint8_t* end) : octets(start, end) {}
+ uint32_t encodedSize() const { return lenwidth + octets.size(); }
+ void encode(Buffer& buffer) {
+ buffer.putUInt<lenwidth>(octets.size());
+ if (octets.size() > 0)
+ buffer.putRawData(&octets[0], octets.size());
+ };
+ void decode(Buffer& buffer) {
+ uint32_t len = buffer.getUInt<lenwidth>();
+ octets.resize(len);
+ if (len > 0)
+ buffer.getRawData(&octets[0], len);
+ }
+ bool operator==(const Data& d) const {
+ const VariableWidthValue<lenwidth>* rhs = dynamic_cast< const VariableWidthValue<lenwidth>* >(&d);
+ if (rhs == 0) return false;
+ else return octets==rhs->octets;
+ }
+
+ bool convertsToString() const { return true; }
+ std::string getString() const { return std::string(octets.begin(), octets.end()); }
+
+ void print(std::ostream& o) const { o << "V" << lenwidth << ":" << octets.size() << ":"; };
+};
+
+template <class T>
+class EncodedValue : public FieldValue::Data {
+ T value;
+ public:
+
+ EncodedValue() {}
+ EncodedValue(const T& v) : value(v) {}
+
+ T& getValue() { return value; }
+ const T& getValue() const { return value; }
+
+ uint32_t encodedSize() const { return value.encodedSize(); }
+
+ void encode(Buffer& buffer) {
+ value.encode(buffer);
+ };
+ void decode(Buffer& buffer) {
+ value.decode(buffer);
+ }
+ bool operator==(const Data& d) const {
+ const EncodedValue<T>* rhs = dynamic_cast< const EncodedValue<T>* >(&d);
+ if (rhs == 0) return false;
+ else return value==rhs->value;
+ }
+
+ void print(std::ostream& o) const { o << "[" << value << "]"; };
+};
+
+class Str8Value : public FieldValue {
+ public:
+ Str8Value(const std::string& v);
+};
+
+class Str16Value : public FieldValue {
+ public:
+ Str16Value(const std::string& v);
+};
+
+class Struct32Value : public FieldValue {
+ public:
+ Struct32Value(const std::string& v);
+};
+
+class FloatValue : public FieldValue
+{
+ public:
+ FloatValue(float f);
+};
+class DoubleValue : public FieldValue
+{
+ public:
+ DoubleValue(double f);
+};
+
+/*
+ * Basic integer value encodes as signed 32 bit
+ */
+class IntegerValue : public FieldValue {
+ public:
+ IntegerValue(int v);
+};
+
+class TimeValue : public FieldValue {
+ public:
+ TimeValue(uint64_t v);
+};
+
+class Integer64Value : public FieldValue {
+ public:
+ Integer64Value(int64_t v);
+};
+
+class Unsigned64Value : public FieldValue {
+ public:
+ Unsigned64Value(uint64_t v);
+};
+
+class FieldTableValue : public FieldValue {
+ public:
+ FieldTableValue(const FieldTable&);
+};
+
+class ArrayValue : public FieldValue {
+ public:
+ ArrayValue(const Array&);
+};
+
+template <class T>
+bool getEncodedValue(FieldTable::ValuePtr vptr, T& value)
+{
+ if (vptr) {
+ const EncodedValue<T>* ev = dynamic_cast< EncodedValue<T>* >(&(vptr->getData()));
+ if (ev != 0) {
+ value = ev->getValue();
+ return true;
+ }
+ }
+ return false;
+}
+
+
+}} // qpid::framing
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/framing/FrameDecoder.cpp b/RC9/qpid/cpp/src/qpid/framing/FrameDecoder.cpp
new file mode 100644
index 0000000000..07e2f7513d
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/FrameDecoder.cpp
@@ -0,0 +1,68 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "FrameDecoder.h"
+#include "Buffer.h"
+#include "qpid/log/Statement.h"
+#include <algorithm>
+
+namespace qpid {
+namespace framing {
+
+namespace {
+/** Move up to n bytes from start of buf to end of bytes. */
+void move(std::vector<char>& bytes, Buffer& buffer, size_t n) {
+ size_t oldSize = bytes.size();
+ n = std::min(n, size_t(buffer.available()));
+ bytes.resize(oldSize+n);
+ char* p = &bytes[oldSize];
+ buffer.getRawData(reinterpret_cast<uint8_t*>(p), n);
+}
+}
+
+bool FrameDecoder::decode(Buffer& buffer) {
+ if (buffer.available() == 0) return false;
+ if (fragment.empty()) {
+ if (frame.decode(buffer)) // Decode from buffer
+ return true;
+ else // Store fragment
+ move(fragment, buffer, buffer.available());
+ }
+ else { // Already have a fragment
+ // Get enough data to decode the frame size.
+ if (fragment.size() < AMQFrame::DECODE_SIZE_MIN) {
+ move(fragment, buffer, AMQFrame::DECODE_SIZE_MIN - fragment.size());
+ }
+ if (fragment.size() >= AMQFrame::DECODE_SIZE_MIN) {
+ uint16_t size = AMQFrame::decodeSize(&fragment[0]);
+ assert(size > fragment.size());
+ move(fragment, buffer, size-fragment.size());
+ Buffer b(&fragment[0], fragment.size());
+ if (frame.decode(b)) {
+ assert(b.available() == 0);
+ fragment.clear();
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+}} // namespace qpid::framing
diff --git a/RC9/qpid/cpp/src/qpid/framing/FrameDecoder.h b/RC9/qpid/cpp/src/qpid/framing/FrameDecoder.h
new file mode 100644
index 0000000000..7f974dadc3
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/FrameDecoder.h
@@ -0,0 +1,44 @@
+#ifndef QPID_FRAMING_FRAMEDECODER_H
+#define QPID_FRAMING_FRAMEDECODER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "AMQFrame.h"
+
+namespace qpid {
+namespace framing {
+
+/**
+ * Decode a frame from buffer. If buffer does not contain a complete
+ * frame, caches the fragment for the next call to decode.
+ */
+class FrameDecoder
+{
+ public:
+ bool decode(Buffer& buffer);
+ AMQFrame frame;
+ private:
+ std::vector<char> fragment;
+};
+}} // namespace qpid::framing
+
+#endif /*!QPID_FRAMING_FRAMEDECODER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/framing/FrameDefaultVisitor.h b/RC9/qpid/cpp/src/qpid/framing/FrameDefaultVisitor.h
new file mode 100644
index 0000000000..bd676960bf
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/FrameDefaultVisitor.h
@@ -0,0 +1,60 @@
+#ifndef QPID_FRAMING_FRAMEVISITOR_H
+#define QPID_FRAMING_FRAMEVISITOR_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/framing/MethodBodyDefaultVisitor.h"
+#include "qpid/framing/AMQBody.h"
+#include "qpid/framing/AMQMethodBody.h"
+#include "qpid/framing/AMQHeaderBody.h"
+#include "qpid/framing/AMQContentBody.h"
+#include "qpid/framing/AMQHeartbeatBody.h"
+
+namespace qpid {
+namespace framing {
+/**
+ * Visitor for all concrete frame body types, which combines
+ * AMQBodyConstVisitor and MethodBodyDefaultVisitor.
+ *
+ * Derived classes can override visit methods to specify actions.
+ * Derived classes must override defaultVisit(), which is called
+ * for any non-overridden visit functions.
+ *
+ */
+struct FrameDefaultVisitor : public AMQBodyConstVisitor,
+ protected MethodBodyDefaultVisitor
+{
+ virtual void defaultVisit(const AMQBody&) = 0;
+ void defaultVisit(const AMQMethodBody& method) { defaultVisit(static_cast<const AMQBody&>(method)); }
+
+ void visit(const AMQHeaderBody& b) { defaultVisit(b); }
+ void visit(const AMQContentBody& b) { defaultVisit(b); }
+ void visit(const AMQHeartbeatBody& b) { defaultVisit(b); }
+ void visit(const AMQMethodBody& b) { b.accept(static_cast<MethodBodyDefaultVisitor&>(*this)); }
+
+ using AMQBodyConstVisitor::visit;
+ using MethodBodyDefaultVisitor::visit;
+};
+
+}} // namespace qpid::framing
+
+
+#endif /*!QPID_FRAMING_FRAMEVISITOR_H*/
diff --git a/RC9/qpid/cpp/src/qpid/framing/FrameHandler.h b/RC9/qpid/cpp/src/qpid/framing/FrameHandler.h
new file mode 100644
index 0000000000..457968c35e
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/FrameHandler.h
@@ -0,0 +1,33 @@
+#ifndef QPID_FRAMING_FRAMEHANDLER_H
+#define QPID_FRAMING_FRAMEHANDLER_H
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "Handler.h"
+
+namespace qpid {
+namespace framing {
+
+class AMQFrame;
+typedef Handler<AMQFrame&> FrameHandler;
+
+
+}}
+#endif /*!QPID_FRAMING_FRAMEHANDLER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/framing/FrameSet.cpp b/RC9/qpid/cpp/src/qpid/framing/FrameSet.cpp
new file mode 100644
index 0000000000..9846f1d42b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/FrameSet.cpp
@@ -0,0 +1,90 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "FrameSet.h"
+#include "qpid/framing/all_method_bodies.h"
+#include "qpid/framing/frame_functors.h"
+#include "qpid/framing/MessageProperties.h"
+#include "qpid/framing/TypeFilter.h"
+
+using namespace qpid::framing;
+using namespace boost;
+
+FrameSet::FrameSet(const SequenceNumber& _id) : id(_id),contentSize(0),recalculateSize(true) { }
+
+void FrameSet::append(const AMQFrame& part)
+{
+ parts.push_back(part);
+ recalculateSize = true;
+}
+
+bool FrameSet::isComplete() const
+{
+ return !parts.empty() && parts.back().getEof() && parts.back().getEos();
+}
+
+bool FrameSet::isContentBearing() const
+{
+ const AMQMethodBody* method = getMethod();
+ return method && method->isContentBearing();
+}
+
+const AMQMethodBody* FrameSet::getMethod() const
+{
+ return parts.empty() ? 0 : parts[0].getMethod();
+}
+
+const AMQHeaderBody* FrameSet::getHeaders() const
+{
+ return parts.size() < 2 ? 0 : parts[1].castBody<AMQHeaderBody>();
+}
+
+AMQHeaderBody* FrameSet::getHeaders()
+{
+ return parts.size() < 2 ? 0 : parts[1].castBody<AMQHeaderBody>();
+}
+
+uint64_t FrameSet::getContentSize() const
+{
+ if (recalculateSize)
+ {
+ SumBodySize sum;
+ map_if(sum, TypeFilter<CONTENT_BODY>());
+ contentSize = sum.getSize();
+ recalculateSize = false;
+ }
+ return contentSize;
+}
+
+void FrameSet::getContent(std::string& out) const {
+ out.clear();
+ out.reserve(getContentSize());
+ for(Frames::const_iterator i = parts.begin(); i != parts.end(); i++) {
+ if (i->getBody()->type() == CONTENT_BODY)
+ out += i->castBody<AMQContentBody>()->getData();
+ }
+}
+
+std::string FrameSet::getContent() const {
+ std::string out;
+ getContent(out);
+ return out;
+}
diff --git a/RC9/qpid/cpp/src/qpid/framing/FrameSet.h b/RC9/qpid/cpp/src/qpid/framing/FrameSet.h
new file mode 100644
index 0000000000..82987910a7
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/FrameSet.h
@@ -0,0 +1,107 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <string>
+#include "qpid/InlineVector.h"
+#include "qpid/framing/amqp_framing.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/SequenceNumber.h"
+
+#ifndef _FrameSet_
+#define _FrameSet_
+
+namespace qpid {
+namespace framing {
+
+/**
+ * Collects the frames representing a message.
+ */
+class FrameSet
+{
+ typedef InlineVector<AMQFrame, 4> Frames;
+ const SequenceNumber id;
+ Frames parts;
+ mutable uint64_t contentSize;
+ mutable bool recalculateSize;
+
+public:
+ typedef boost::shared_ptr<FrameSet> shared_ptr;
+
+ FrameSet(const SequenceNumber& id);
+ void append(const AMQFrame& part);
+ bool isComplete() const;
+
+ uint64_t getContentSize() const;
+ void getContent(std::string&) const;
+ std::string getContent() const;
+
+ bool isContentBearing() const;
+
+ const AMQMethodBody* getMethod() const;
+ const AMQHeaderBody* getHeaders() const;
+ AMQHeaderBody* getHeaders();
+
+ template <class T> bool isA() const {
+ const AMQMethodBody* method = getMethod();
+ return method && method->isA<T>();
+ }
+
+ template <class T> const T* as() const {
+ const AMQMethodBody* method = getMethod();
+ return (method && method->isA<T>()) ? dynamic_cast<const T*>(method) : 0;
+ }
+
+ template <class T> const T* getHeaderProperties() const {
+ const AMQHeaderBody* header = getHeaders();
+ return header ? header->get<T>() : 0;
+ }
+
+ const SequenceNumber& getId() const { return id; }
+
+ template <class P> void remove(P predicate) {
+ parts.erase(std::remove_if(parts.begin(), parts.end(), predicate), parts.end());
+ }
+
+ template <class F> void map(F& functor) {
+ std::for_each(parts.begin(), parts.end(), functor);
+ }
+
+ template <class F> void map(F& functor) const {
+ std::for_each(parts.begin(), parts.end(), functor);
+ }
+
+ template <class F, class P> void map_if(F& functor, P predicate) {
+ for(Frames::iterator i = parts.begin(); i != parts.end(); i++) {
+ if (predicate(*i)) functor(*i);
+ }
+ }
+
+ template <class F, class P> void map_if(F& functor, P predicate) const {
+ for(Frames::const_iterator i = parts.begin(); i != parts.end(); i++) {
+ if (predicate(*i)) functor(*i);
+ }
+ }
+};
+
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/framing/Handler.h b/RC9/qpid/cpp/src/qpid/framing/Handler.h
new file mode 100644
index 0000000000..e07a803e17
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/Handler.h
@@ -0,0 +1,101 @@
+#ifndef QPID_FRAMING_HANDLER_H
+#define QPID_FRAMING_HANDLER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/shared_ptr.h"
+#include <boost/type_traits/remove_reference.hpp>
+#include <assert.h>
+
+namespace qpid {
+namespace framing {
+
+template <class T>
+struct Handler {
+ typedef T HandledType;
+ typedef void handleFptr(T);
+ typedef void result_type; // Compatible with std/boost functors.
+
+ Handler(Handler<T>* next_=0) : next(next_) {}
+ virtual ~Handler() {}
+ virtual void handle(T) = 0;
+
+ /** Allow functor syntax for calling handle */
+ void operator()(T t) { handle(t); }
+
+
+ /** Pointer to next handler in a linked list. */
+ Handler<T>* next;
+
+ /** Adapt any void(T) functor as a Handler.
+ * Functor<F>(f) will copy f.
+ * Functor<F&>(f) will only take a reference to x.
+ */
+ template <class F> class Functor : public Handler<T> {
+ public:
+ Functor(F f, Handler<T>* next=0) : Handler<T>(next), functor(f) {}
+ void handle(T t) { functor(t); }
+ private:
+ F functor;
+ };
+
+ /** Adapt a member function of X as a Handler.
+ * Only holds a reference to its target, not a copy.
+ */
+ template <class X, void (X::*F)(T)>
+ class MemFunRef : public Handler<T> {
+ public:
+ MemFunRef(X& x, Handler<T>* next=0) : Handler(next), target(&x) {}
+ void handle(T t) { (target->*F)(t); }
+
+ /** Allow calling with -> syntax */
+ MemFunRef* operator->() { return this; }
+
+ private:
+ X* target;
+ };
+
+ /** Interface for a handler that implements a
+ * pair of in/out handle operations.
+ * @see InOutHandler
+ */
+ class InOutHandlerInterface {
+ public:
+ virtual ~InOutHandlerInterface() {}
+ virtual void handleIn(T) = 0;
+ virtual void handleOut(T) = 0;
+ };
+
+ /** Support for implementing an in-out handler pair as a single class.
+ * Overrides handleIn, handleOut functions in a single class.
+ */
+ struct InOutHandler : protected InOutHandlerInterface {
+ InOutHandler(Handler<T>* nextIn=0, Handler<T>* nextOut=0) : in(*this, nextIn), out(*this, nextOut) {}
+ MemFunRef<InOutHandlerInterface, &InOutHandlerInterface::handleIn> in;
+ MemFunRef<InOutHandlerInterface, &InOutHandlerInterface::handleOut> out;
+ };
+};
+
+
+
+}}
+#endif /*!QPID_FRAMING_HANDLER_H*/
+//
diff --git a/RC9/qpid/cpp/src/qpid/framing/HeaderProperties.h b/RC9/qpid/cpp/src/qpid/framing/HeaderProperties.h
new file mode 100644
index 0000000000..39c448fc3c
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/HeaderProperties.h
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "amqp_types.h"
+#include "Buffer.h"
+
+#ifndef _HeaderProperties_
+#define _HeaderProperties_
+
+namespace qpid {
+namespace framing {
+
+ class HeaderProperties
+ {
+
+ public:
+ inline virtual ~HeaderProperties(){}
+ virtual uint8_t classId() const = 0;
+ virtual uint32_t encodedSize() const = 0;
+ virtual void encode(Buffer& buffer) const = 0;
+ virtual void decode(Buffer& buffer, uint32_t size) = 0;
+ };
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/framing/InitiationHandler.cpp b/RC9/qpid/cpp/src/qpid/framing/InitiationHandler.cpp
new file mode 100644
index 0000000000..eceeaf4abc
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/InitiationHandler.cpp
@@ -0,0 +1,24 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "InitiationHandler.h"
+
+qpid::framing::InitiationHandler::~InitiationHandler() {}
diff --git a/RC9/qpid/cpp/src/qpid/framing/InitiationHandler.h b/RC9/qpid/cpp/src/qpid/framing/InitiationHandler.h
new file mode 100644
index 0000000000..16a6b502e8
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/InitiationHandler.h
@@ -0,0 +1,41 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <string>
+
+#ifndef _InitiationHandler_
+#define _InitiationHandler_
+
+#include "ProtocolInitiation.h"
+
+namespace qpid {
+namespace framing {
+
+ class InitiationHandler{
+ public:
+ virtual ~InitiationHandler();
+ virtual void initiated(const ProtocolInitiation&) = 0;
+ };
+
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/framing/InputHandler.h b/RC9/qpid/cpp/src/qpid/framing/InputHandler.h
new file mode 100644
index 0000000000..3a6d786a24
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/InputHandler.h
@@ -0,0 +1,41 @@
+#ifndef _InputHandler_
+#define _InputHandler_
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "FrameHandler.h"
+#include <boost/noncopyable.hpp>
+
+namespace qpid {
+namespace framing {
+
+// TODO aconway 2007-08-29: Eliminate, replace with FrameHandler.
+class InputHandler : public FrameHandler {
+ public:
+ virtual ~InputHandler() {}
+ virtual void received(AMQFrame&) = 0;
+ void handle(AMQFrame& f) { received(f); }
+};
+
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/framing/Invoker.h b/RC9/qpid/cpp/src/qpid/framing/Invoker.h
new file mode 100644
index 0000000000..4f1cf7c331
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/Invoker.h
@@ -0,0 +1,86 @@
+#ifndef QPID_FRAMING_INVOKER_H
+#define QPID_FRAMING_INVOKER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/framing/AMQMethodBody.h"
+#include "qpid/framing/MethodBodyDefaultVisitor.h"
+#include "qpid/framing/StructHelper.h"
+
+#include <boost/optional.hpp>
+
+namespace qpid {
+namespace framing {
+
+class AMQMethodBody;
+
+/**
+ * Base class for invoker visitors.
+ */
+class Invoker: public MethodBodyDefaultVisitor, protected StructHelper
+{
+ public:
+ struct Result {
+ public:
+ Result() : handled(false) {}
+ const std::string& getResult() const { return result; }
+ bool hasResult() const { return !result.empty(); }
+ bool wasHandled() const { return handled; }
+ operator bool() const { return handled; }
+
+ std::string result;
+ bool handled;
+ };
+
+ void defaultVisit(const AMQMethodBody&) {}
+ Result getResult() const { return result; }
+
+ protected:
+ Result result;
+};
+
+/**
+ * Invoke an invocable object.
+ * Invocable classes must provide a nested type Invoker.
+ */
+template <class Invocable>
+Invoker::Result invoke(Invocable& target, const AMQMethodBody& body) {
+ typename Invocable::Invoker invoker(target);
+ body.accept(invoker);
+ return invoker.getResult();
+}
+
+/**
+ * Invoke an invocable object.
+ * Invocable classes must provide a nested type Invoker.
+ */
+template <class Invocable>
+Invoker::Result invoke(Invocable& target, const AMQBody& body) {
+ typename Invocable::Invoker invoker(target);
+ const AMQMethodBody* method = body.getMethod();
+ if (method)
+ method->accept(invoker);
+ return invoker.getResult();
+}
+
+}} // namespace qpid::framing
+
+#endif /*!QPID_FRAMING_INVOKER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/framing/MethodContent.h b/RC9/qpid/cpp/src/qpid/framing/MethodContent.h
new file mode 100644
index 0000000000..737c0d6b7b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/MethodContent.h
@@ -0,0 +1,40 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _MethodContent_
+#define _MethodContent_
+
+#include <string>
+#include "AMQHeaderBody.h"
+
+namespace qpid {
+namespace framing {
+
+class MethodContent
+{
+public:
+ virtual ~MethodContent() {}
+ //TODO: rethink this interface
+ virtual AMQHeaderBody getHeader() const = 0;
+ virtual const std::string& getData() const = 0;
+};
+
+}}
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/framing/ModelMethod.h b/RC9/qpid/cpp/src/qpid/framing/ModelMethod.h
new file mode 100644
index 0000000000..afbdf7b6e2
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/ModelMethod.h
@@ -0,0 +1,49 @@
+#ifndef _ModelMethod_
+#define _ModelMethod_
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "AMQMethodBody.h"
+#include "qpid/framing/Header.h"
+
+namespace qpid {
+namespace framing {
+
+
+class ModelMethod : public AMQMethodBody
+{
+ mutable Header header;
+public:
+ virtual ~ModelMethod() {}
+ virtual void encodeHeader(Buffer& buffer) const { header.encode(buffer); }
+ virtual void decodeHeader(Buffer& buffer, uint32_t size=0) { header.decode(buffer, size); }
+ virtual uint32_t headerSize() const { return header.encodedSize(); }
+ virtual bool isSync() const { return header.getSync(); }
+ virtual void setSync(bool on) const { header.setSync(on); }
+ Header& getHeader() { return header; }
+ const Header& getHeader() const { return header; }
+};
+
+
+}} // namespace qpid::framing
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/framing/OutputHandler.h b/RC9/qpid/cpp/src/qpid/framing/OutputHandler.h
new file mode 100644
index 0000000000..6f4b27fb72
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/OutputHandler.h
@@ -0,0 +1,42 @@
+#ifndef _OutputHandler_
+#define _OutputHandler_
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <boost/noncopyable.hpp>
+#include "FrameHandler.h"
+
+namespace qpid {
+namespace framing {
+
+// TODO aconway 2007-08-29: Replace with FrameHandler.
+class OutputHandler : public FrameHandler {
+ public:
+ virtual ~OutputHandler() {}
+ virtual void send(AMQFrame&) = 0;
+ void handle(AMQFrame& f) { send(f); }
+};
+
+
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/framing/ProtocolInitiation.cpp b/RC9/qpid/cpp/src/qpid/framing/ProtocolInitiation.cpp
new file mode 100644
index 0000000000..50617de017
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/ProtocolInitiation.cpp
@@ -0,0 +1,66 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "ProtocolInitiation.h"
+
+namespace qpid {
+namespace framing {
+
+ProtocolInitiation::ProtocolInitiation(){}
+
+ProtocolInitiation::ProtocolInitiation(uint8_t _major, uint8_t _minor) : version(_major, _minor) {}
+
+ProtocolInitiation::ProtocolInitiation(ProtocolVersion p) : version(p) {}
+
+ProtocolInitiation::~ProtocolInitiation(){}
+
+void ProtocolInitiation::encode(Buffer& buffer) const {
+ buffer.putOctet('A');
+ buffer.putOctet('M');
+ buffer.putOctet('Q');
+ buffer.putOctet('P');
+ buffer.putOctet(1);//class
+ buffer.putOctet(1);//instance
+ buffer.putOctet(version.getMajor());
+ buffer.putOctet(version.getMinor());
+}
+
+bool ProtocolInitiation::decode(Buffer& buffer){
+ if(buffer.available() >= 8){
+ buffer.getOctet();//A
+ buffer.getOctet();//M
+ buffer.getOctet();//Q
+ buffer.getOctet();//P
+ buffer.getOctet();//class
+ buffer.getOctet();//instance
+ version.setMajor(buffer.getOctet());
+ version.setMinor(buffer.getOctet());
+ return true;
+ }else{
+ return false;
+ }
+}
+
+
+std::ostream& operator<<(std::ostream& o, const framing::ProtocolInitiation& pi) {
+ return o << int(pi.getMajor()) << "-" << int(pi.getMinor());
+}
+
+}} // namespace qpid::framing
diff --git a/RC9/qpid/cpp/src/qpid/framing/ProtocolInitiation.h b/RC9/qpid/cpp/src/qpid/framing/ProtocolInitiation.h
new file mode 100644
index 0000000000..6584fee55c
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/ProtocolInitiation.h
@@ -0,0 +1,58 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "amqp_types.h"
+#include "Buffer.h"
+#include "AMQDataBlock.h"
+#include "ProtocolVersion.h"
+
+#ifndef _ProtocolInitiation_
+#define _ProtocolInitiation_
+
+namespace qpid {
+namespace framing {
+
+class ProtocolInitiation : public AMQDataBlock
+{
+private:
+ ProtocolVersion version;
+
+public:
+ ProtocolInitiation();
+ ProtocolInitiation(uint8_t major, uint8_t minor);
+ ProtocolInitiation(ProtocolVersion p);
+ virtual ~ProtocolInitiation();
+ virtual void encode(Buffer& buffer) const;
+ virtual bool decode(Buffer& buffer);
+ inline virtual uint32_t encodedSize() const { return 8; }
+ inline uint8_t getMajor() const { return version.getMajor(); }
+ inline uint8_t getMinor() const { return version.getMinor(); }
+ inline ProtocolVersion getVersion() const { return version; }
+ bool operator==(ProtocolVersion v) const { return v == getVersion(); }
+};
+
+std::ostream& operator<<(std::ostream& o, const framing::ProtocolInitiation& pi);
+
+
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/framing/ProtocolVersion.cpp b/RC9/qpid/cpp/src/qpid/framing/ProtocolVersion.cpp
new file mode 100644
index 0000000000..7a96bfa925
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/ProtocolVersion.cpp
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "ProtocolVersion.h"
+#include <sstream>
+
+using namespace qpid::framing;
+
+const std::string ProtocolVersion::toString() const
+{
+ std::stringstream ss;
+ ss << major_ << "-" << minor_;
+ return ss.str();
+}
+
+ProtocolVersion& ProtocolVersion::operator=(ProtocolVersion p)
+{
+ major_ = p.major_;
+ minor_ = p.minor_;
+ return *this;
+}
+
+bool ProtocolVersion::operator==(ProtocolVersion p) const
+{
+ return major_ == p.major_ && minor_ == p.minor_;
+}
+
diff --git a/RC9/qpid/cpp/src/qpid/framing/ProtocolVersion.h b/RC9/qpid/cpp/src/qpid/framing/ProtocolVersion.h
new file mode 100644
index 0000000000..9a7ebec491
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/ProtocolVersion.h
@@ -0,0 +1,57 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _ProtocolVersion_
+#define _ProtocolVersion_
+
+#include "amqp_types.h"
+
+namespace qpid
+{
+namespace framing
+{
+
+class ProtocolVersion
+{
+private:
+ uint8_t major_;
+ uint8_t minor_;
+
+public:
+ explicit ProtocolVersion(uint8_t _major=0, uint8_t _minor=0)
+ : major_(_major), minor_(_minor) {}
+
+ uint8_t getMajor() const { return major_; }
+ void setMajor(uint8_t major) { major_ = major; }
+ uint8_t getMinor() const { return minor_; }
+ void setMinor(uint8_t minor) { minor_ = minor; }
+ const std::string toString() const;
+
+ ProtocolVersion& operator=(ProtocolVersion p);
+
+ bool operator==(ProtocolVersion p) const;
+ bool operator!=(ProtocolVersion p) const { return ! (*this == p); }
+};
+
+} // namespace framing
+} // namespace qpid
+
+
+#endif // ifndef _ProtocolVersion_
diff --git a/RC9/qpid/cpp/src/qpid/framing/Proxy.cpp b/RC9/qpid/cpp/src/qpid/framing/Proxy.cpp
new file mode 100644
index 0000000000..6b37fb368d
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/Proxy.cpp
@@ -0,0 +1,42 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "Proxy.h"
+#include "AMQFrame.h"
+
+namespace qpid {
+namespace framing {
+
+Proxy::Proxy(FrameHandler& h) : out(&h) {}
+
+Proxy::~Proxy() {}
+
+void Proxy::send(const AMQBody& b) {
+ AMQFrame f(b);
+ out->handle(f);
+}
+
+ProtocolVersion Proxy::getVersion() const {
+ return ProtocolVersion();
+}
+
+FrameHandler& Proxy::getHandler() { return *out; }
+
+void Proxy::setHandler(FrameHandler& f) { out=&f; }
+
+}} // namespace qpid::framing
diff --git a/RC9/qpid/cpp/src/qpid/framing/Proxy.h b/RC9/qpid/cpp/src/qpid/framing/Proxy.h
new file mode 100644
index 0000000000..3dc082097a
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/Proxy.h
@@ -0,0 +1,54 @@
+#ifndef _framing_Proxy_h
+#define _framing_Proxy_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "FrameHandler.h"
+#include "ProtocolVersion.h"
+
+namespace qpid {
+namespace framing {
+
+class AMQBody;
+
+/**
+ * Base class for proxies.
+ */
+class Proxy
+{
+ public:
+ Proxy(FrameHandler& h);
+ virtual ~Proxy();
+
+ void send(const AMQBody&);
+
+ ProtocolVersion getVersion() const;
+
+ FrameHandler& getHandler();
+ void setHandler(FrameHandler&);
+
+ private:
+ FrameHandler* out;
+};
+
+}} // namespace qpid::framing
+
+
+
+#endif /*!_framing_Proxy_h*/
diff --git a/RC9/qpid/cpp/src/qpid/framing/SendContent.cpp b/RC9/qpid/cpp/src/qpid/framing/SendContent.cpp
new file mode 100644
index 0000000000..f390106dee
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/SendContent.cpp
@@ -0,0 +1,69 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "SendContent.h"
+
+qpid::framing::SendContent::SendContent(FrameHandler& h, uint16_t mfs, uint efc) : handler(h),
+ maxFrameSize(mfs),
+ expectedFrameCount(efc), frameCount(0) {}
+
+void qpid::framing::SendContent::operator()(const AMQFrame& f)
+{
+ bool first = frameCount == 0;
+ bool last = ++frameCount == expectedFrameCount;
+
+ /*end of frame marker is included in frameOverhead() but not in
+ real frame size, hence substract -1 from frameOverhead()*/
+ uint16_t maxContentSize = maxFrameSize - (AMQFrame::frameOverhead() - 1);
+ const AMQContentBody* body(f.castBody<AMQContentBody>());
+ if (body->encodedSize() > maxContentSize) {
+ uint32_t offset = 0;
+ for (int chunk = body->encodedSize() / maxContentSize; chunk > 0; chunk--) {
+ sendFragment(*body, offset, maxContentSize, first && offset == 0, last && offset + maxContentSize == body->encodedSize());
+ offset += maxContentSize;
+ }
+ uint32_t remainder = body->encodedSize() % maxContentSize;
+ if (remainder) {
+ sendFragment(*body, offset, remainder, first && offset == 0, last);
+ }
+ } else {
+ AMQFrame copy(f);
+ setFlags(copy, first, last);
+ handler.handle(copy);
+ }
+}
+
+void qpid::framing::SendContent::sendFragment(const AMQContentBody& body, uint32_t offset, uint16_t size, bool first, bool last) const
+{
+ AMQFrame fragment(in_place<AMQContentBody>(
+ body.getData().substr(offset, size)));
+ setFlags(fragment, first, last);
+ handler.handle(fragment);
+}
+
+void qpid::framing::SendContent::setFlags(AMQFrame& f, bool first, bool last) const
+{
+ f.setBof(false);
+ f.setBos(first);
+ f.setEof(true);//content is always the last segment
+ f.setEos(last);
+}
+
diff --git a/RC9/qpid/cpp/src/qpid/framing/SendContent.h b/RC9/qpid/cpp/src/qpid/framing/SendContent.h
new file mode 100644
index 0000000000..dcd5202b3e
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/SendContent.h
@@ -0,0 +1,55 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <string>
+#include "qpid/framing/amqp_framing.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/FrameHandler.h"
+
+#ifndef _SendContent_
+#define _SendContent_
+
+namespace qpid {
+namespace framing {
+
+/**
+ * Functor that sends frame to handler, refragmenting if
+ * necessary. Currently only works on content frames but this could be
+ * changed once we support multi-frame segments in general.
+ */
+class SendContent
+{
+ mutable FrameHandler& handler;
+ const uint16_t maxFrameSize;
+ uint expectedFrameCount;
+ uint frameCount;
+
+ void sendFragment(const AMQContentBody& body, uint32_t offset, uint16_t size, bool first, bool last) const;
+ void setFlags(AMQFrame& f, bool first, bool last) const;
+public:
+ SendContent(FrameHandler& _handler, uint16_t _maxFrameSize, uint frameCount);
+ void operator()(const AMQFrame& f);
+};
+
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/framing/SequenceNumber.cpp b/RC9/qpid/cpp/src/qpid/framing/SequenceNumber.cpp
new file mode 100644
index 0000000000..cac4e6681e
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/SequenceNumber.cpp
@@ -0,0 +1,110 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "SequenceNumber.h"
+#include "Buffer.h"
+#include <ostream>
+
+using qpid::framing::SequenceNumber;
+using qpid::framing::Buffer;
+
+SequenceNumber::SequenceNumber() : value(0) {}
+
+SequenceNumber::SequenceNumber(uint32_t v) : value((int32_t) v) {}
+
+bool SequenceNumber::operator==(const SequenceNumber& other) const
+{
+ return value == other.value;
+}
+
+bool SequenceNumber::operator!=(const SequenceNumber& other) const
+{
+ return !(value == other.value);
+}
+
+
+SequenceNumber& SequenceNumber::operator++()
+{
+ value = value + 1;
+ return *this;
+}
+
+const SequenceNumber SequenceNumber::operator++(int)
+{
+ SequenceNumber old(value);
+ value = value + 1;
+ return old;
+}
+
+SequenceNumber& SequenceNumber::operator--()
+{
+ value = value - 1;
+ return *this;
+}
+
+bool SequenceNumber::operator<(const SequenceNumber& other) const
+{
+ return (value - other.value) < 0;
+}
+
+bool SequenceNumber::operator>(const SequenceNumber& other) const
+{
+ return other < *this;
+}
+
+bool SequenceNumber::operator<=(const SequenceNumber& other) const
+{
+ return *this == other || *this < other;
+}
+
+bool SequenceNumber::operator>=(const SequenceNumber& other) const
+{
+ return *this == other || *this > other;
+}
+
+void SequenceNumber::encode(Buffer& buffer) const
+{
+ buffer.putLong(value);
+}
+
+void SequenceNumber::decode(Buffer& buffer)
+{
+ value = buffer.getLong();
+}
+
+uint32_t SequenceNumber::encodedSize() const {
+ return 4;
+}
+
+namespace qpid {
+namespace framing {
+
+int32_t operator-(const SequenceNumber& a, const SequenceNumber& b)
+{
+ int32_t result = a.value - b.value;
+ return result;
+}
+
+std::ostream& operator<<(std::ostream& o, const SequenceNumber& n) {
+ return o << n.getValue();
+}
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/framing/SequenceNumber.h b/RC9/qpid/cpp/src/qpid/framing/SequenceNumber.h
new file mode 100644
index 0000000000..930e146863
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/SequenceNumber.h
@@ -0,0 +1,75 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _framing_SequenceNumber_h
+#define _framing_SequenceNumber_h
+
+#include "amqp_types.h"
+#include <iosfwd>
+
+namespace qpid {
+namespace framing {
+
+class Buffer;
+
+/**
+ * 4-byte sequence number that 'wraps around'.
+ */
+class SequenceNumber
+{
+ int32_t value;
+
+ public:
+ SequenceNumber();
+ SequenceNumber(uint32_t v);
+
+ SequenceNumber& operator++();//prefix ++
+ const SequenceNumber operator++(int);//postfix ++
+ SequenceNumber& operator--();//prefix ++
+ bool operator==(const SequenceNumber& other) const;
+ bool operator!=(const SequenceNumber& other) const;
+ bool operator<(const SequenceNumber& other) const;
+ bool operator>(const SequenceNumber& other) const;
+ bool operator<=(const SequenceNumber& other) const;
+ bool operator>=(const SequenceNumber& other) const;
+ uint32_t getValue() const { return (uint32_t) value; }
+ operator uint32_t() const { return (uint32_t) value; }
+
+ friend int32_t operator-(const SequenceNumber& a, const SequenceNumber& b);
+
+ void encode(Buffer& buffer) const;
+ void decode(Buffer& buffer);
+ uint32_t encodedSize() const;
+
+ template <class S> void serialize(S& s) { s(value); }
+};
+
+struct Window
+{
+ SequenceNumber hwm;
+ SequenceNumber lwm;
+};
+
+std::ostream& operator<<(std::ostream& o, const SequenceNumber& n);
+
+}} // namespace qpid::framing
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/framing/SequenceNumberSet.cpp b/RC9/qpid/cpp/src/qpid/framing/SequenceNumberSet.cpp
new file mode 100644
index 0000000000..afab9033e5
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/SequenceNumberSet.cpp
@@ -0,0 +1,89 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "SequenceNumberSet.h"
+
+using namespace qpid::framing;
+
+void SequenceNumberSet::encode(Buffer& buffer) const
+{
+ buffer.putShort(size() * 4);
+ for (const_iterator i = begin(); i != end(); i++) {
+ buffer.putLong(i->getValue());
+ }
+}
+
+void SequenceNumberSet::decode(Buffer& buffer)
+{
+ uint16_t count = (buffer.getShort() / 4);
+ for (uint16_t i = 0; i < count; i++) {
+ push_back(SequenceNumber(buffer.getLong()));
+ }
+}
+
+uint32_t SequenceNumberSet::encodedSize() const
+{
+ return 2 /*count*/ + (size() * 4);
+}
+
+SequenceNumberSet SequenceNumberSet::condense() const
+{
+ SequenceNumberSet result;
+ const_iterator last = end();
+ const_iterator start = end();
+ for (const_iterator i = begin(); i != end(); i++) {
+ if (start == end()) {
+ start = i;
+ } else if (*i - *last > 1) {
+ result.push_back(*start);
+ result.push_back(*last);
+ start = i;
+ }
+ last = i;
+ }
+ if (start != end()) {
+ result.push_back(*start);
+ result.push_back(*last);
+ }
+ return result;
+}
+
+void SequenceNumberSet::addRange(const SequenceNumber& start, const SequenceNumber& end)
+{
+ push_back(start);
+ push_back(end);
+}
+
+namespace qpid{
+namespace framing{
+
+std::ostream& operator<<(std::ostream& out, const SequenceNumberSet& set) {
+ out << "{";
+ for (SequenceNumberSet::const_iterator i = set.begin(); i != set.end(); i++) {
+ if (i != set.begin()) out << ", ";
+ out << (i->getValue());
+ }
+ out << "}";
+ return out;
+}
+
+}
+}
diff --git a/RC9/qpid/cpp/src/qpid/framing/SequenceNumberSet.h b/RC9/qpid/cpp/src/qpid/framing/SequenceNumberSet.h
new file mode 100644
index 0000000000..666307f9d9
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/SequenceNumberSet.h
@@ -0,0 +1,68 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _framing_SequenceNumberSet_h
+#define _framing_SequenceNumberSet_h
+
+#include <ostream>
+#include "amqp_types.h"
+#include "Buffer.h"
+#include "SequenceNumber.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/InlineVector.h"
+
+namespace qpid {
+namespace framing {
+
+class SequenceNumberSet : public InlineVector<SequenceNumber, 2>
+{
+ typedef InlineVector<SequenceNumber, 2> Base;
+public:
+ typedef Base::const_iterator const_iterator;
+ typedef Base::iterator iterator;
+
+ void encode(Buffer& buffer) const;
+ void decode(Buffer& buffer);
+ uint32_t encodedSize() const;
+ SequenceNumberSet condense() const;
+ void addRange(const SequenceNumber& start, const SequenceNumber& end);
+
+ template <class T>
+ void processRanges(T& t) const
+ {
+ if (size() % 2) { //must be even number
+ throw InvalidArgumentException("SequenceNumberSet contains odd number of elements");
+ }
+
+ for (SequenceNumberSet::const_iterator i = begin(); i != end(); i++) {
+ SequenceNumber first = *(i);
+ SequenceNumber last = *(++i);
+ t(first, last);
+ }
+ }
+
+ friend std::ostream& operator<<(std::ostream&, const SequenceNumberSet&);
+};
+
+
+}} // namespace qpid::framing
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/framing/SequenceSet.cpp b/RC9/qpid/cpp/src/qpid/framing/SequenceSet.cpp
new file mode 100644
index 0000000000..2046fac3e1
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/SequenceSet.cpp
@@ -0,0 +1,100 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "SequenceSet.h"
+#include "Buffer.h"
+#include "qpid/framing/reply_exceptions.h"
+
+using namespace qpid::framing;
+using std::max;
+using std::min;
+
+namespace qpid {
+namespace framing {
+
+namespace {
+//each range contains 2 numbers, 4 bytes each
+uint16_t RANGE_SIZE = 2 * 4;
+}
+
+void SequenceSet::encode(Buffer& buffer) const
+{
+ buffer.putShort(rangesSize() * RANGE_SIZE);
+ for (RangeIterator i = rangesBegin(); i != rangesEnd(); i++) {
+ buffer.putLong(i->first().getValue());
+ buffer.putLong(i->last().getValue());
+ }
+}
+
+void SequenceSet::decode(Buffer& buffer)
+{
+ uint16_t size = buffer.getShort();
+ uint16_t count = size / RANGE_SIZE;//number of ranges
+ if (size % RANGE_SIZE)
+ throw IllegalArgumentException(QPID_MSG("Invalid size for sequence set: " << size));
+
+ for (uint16_t i = 0; i < count; i++) {
+ add(SequenceNumber(buffer.getLong()), SequenceNumber(buffer.getLong()));
+ }
+}
+
+uint32_t SequenceSet::encodedSize() const {
+ return 2 /*size field*/ + (rangesSize() * RANGE_SIZE);
+}
+
+bool SequenceSet::contains(const SequenceNumber& s) const {
+ return RangeSet<SequenceNumber>::contains(s);
+}
+
+void SequenceSet::add(const SequenceNumber& s) { *this += s; }
+
+void SequenceSet::add(const SequenceNumber& start, const SequenceNumber& finish) {
+ *this += Range<SequenceNumber>::makeClosed(std::min(start,finish), std::max(start, finish));
+}
+
+void SequenceSet::add(const SequenceSet& set) { *this += set; }
+
+void SequenceSet::remove(const SequenceSet& set) { *this -= set; }
+
+void SequenceSet::remove(const SequenceNumber& start, const SequenceNumber& finish) {
+ *this -= Range<SequenceNumber>::makeClosed(std::min(start,finish), std::max(start, finish));
+}
+
+void SequenceSet::remove(const SequenceNumber& s) { *this -= s; }
+
+
+struct RangePrinter {
+ std::ostream& out;
+ RangePrinter(std::ostream& o) : out(o) {}
+ void operator()(SequenceNumber i, SequenceNumber j) const {
+ out << "[" << i.getValue() << "," << j.getValue() << "] ";
+ }
+};
+
+std::ostream& operator<<(std::ostream& o, const SequenceSet& s) {
+ RangePrinter print(o);
+ o << "{ ";
+ s.for_each(print);
+ return o << "}";
+}
+
+}} // namespace qpid::framing
+
diff --git a/RC9/qpid/cpp/src/qpid/framing/SequenceSet.h b/RC9/qpid/cpp/src/qpid/framing/SequenceSet.h
new file mode 100644
index 0000000000..57b9c2c8e1
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/SequenceSet.h
@@ -0,0 +1,68 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _framing_SequenceSet_h
+#define _framing_SequenceSet_h
+
+#include "SequenceNumber.h"
+#include "qpid/RangeSet.h"
+
+namespace qpid {
+namespace framing {
+class Buffer;
+
+class SequenceSet : public RangeSet<SequenceNumber> {
+ public:
+ SequenceSet() {}
+ SequenceSet(const RangeSet<SequenceNumber>& r)
+ : RangeSet<SequenceNumber>(r) {}
+ SequenceSet(const SequenceNumber& s) { add(s); }
+ SequenceSet(const SequenceNumber& start, const SequenceNumber finish) { add(start,finish); }
+
+
+ void encode(Buffer& buffer) const;
+ void decode(Buffer& buffer);
+ uint32_t encodedSize() const;
+
+ bool contains(const SequenceNumber& s) const;
+ void add(const SequenceNumber& s);
+ void add(const SequenceNumber& start, const SequenceNumber& finish); // Closed range
+ void add(const SequenceSet& set);
+ void remove(const SequenceNumber& s);
+ void remove(const SequenceNumber& start, const SequenceNumber& finish); // Closed range
+ void remove(const SequenceSet& set);
+
+ template <class T> void for_each(T& t) const {
+ for (RangeIterator i = rangesBegin(); i != rangesEnd(); i++)
+ t(i->first(), i->last());
+ }
+
+ template <class T> void for_each(const T& t) const {
+ for (RangeIterator i = rangesBegin(); i != rangesEnd(); i++)
+ t(i->first(), i->last());
+ }
+
+ friend std::ostream& operator<<(std::ostream&, const SequenceSet&);
+};
+
+}} // namespace qpid::framing
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/framing/StructHelper.h b/RC9/qpid/cpp/src/qpid/framing/StructHelper.h
new file mode 100644
index 0000000000..e3dce4f5ec
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/StructHelper.h
@@ -0,0 +1,56 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _StructHelper_
+#define _StructHelper_
+
+#include "qpid/Exception.h"
+#include "Buffer.h"
+
+#include <stdlib.h> // For alloca
+
+namespace qpid {
+namespace framing {
+
+class StructHelper
+{
+public:
+
+ template <class T> void encode(const T t, std::string& data) {
+ uint32_t size = t.bodySize() + 2/*type*/;
+ data.resize(size);
+ Buffer wbuffer(const_cast<char*>(data.data()), size);
+ wbuffer.putShort(T::TYPE);
+ t.encodeStructBody(wbuffer);
+ }
+
+ template <class T> void decode(T& t, const std::string& data) {
+ Buffer rbuffer(const_cast<char*>(data.data()), data.length());
+ uint16_t type = rbuffer.getShort();
+ if (type == T::TYPE) {
+ t.decodeStructBody(rbuffer);
+ } else {
+ throw Exception("Type code does not match");
+ }
+ }
+};
+
+}}
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/framing/TemplateVisitor.h b/RC9/qpid/cpp/src/qpid/framing/TemplateVisitor.h
new file mode 100644
index 0000000000..d6d59603f7
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/TemplateVisitor.h
@@ -0,0 +1,89 @@
+#ifndef QPID_FRAMING_TEMPLATEVISITOR_H
+#define QPID_FRAMING_TEMPLATEVISITOR_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <boost/mpl/fold.hpp>
+#include <boost/utility/value_init.hpp>
+
+namespace qpid {
+namespace framing {
+
+/**
+ * Metafunction to generate a visitor class derived from Base, with a
+ * visit for each type in TypeList calling functor F. TypeList may be
+ * any boost::mpl type collection e.g. mpl::list.
+ *
+ * Generated class is: TemplateVisitor<Base, F, TypeList>::type
+ *
+ * @see make_visitor
+ */
+template <class VisitTemplate, class TypeList, class F>
+class TemplateVisitor
+{
+ struct Base : public VisitorBase {
+ F action;
+ Base(F f) : action(f) {}
+ using VisitorBase::visit;
+ };
+
+ template <class B, class T> struct Visit : public B {
+ Visit(F action) : B(action) {}
+ using B::visit;
+ void visit(const T& body) { action(body); }
+ };
+
+ typedef typename boost::mpl::fold<
+ TypeList, Base, Visit<boost::mpl::placeholders::_1,
+ boost::mpl::placeholders::_2>
+ >::type type;
+};
+
+/**
+ * Construct a TemplateVisitor to perform the given action,
+ * for example:
+ * @code
+ */
+template <class VisitorBase, class TypeList, class F>
+TemplateVisitor<VisitorBase,TypeList,F>::type make_visitor(F action) {
+ return TemplateVisitor<VisitorBase,TypeList,F>::type(action);
+};
+
+/**
+ * For method body classes in TypeList, invoke the corresponding function
+ * on Target and return true. For other body types return false.
+ */
+template <class TypeList, class Target>
+bool invoke(const AMQBody& body, Target& target) {
+ typename InvokeVisitor<TypeList, Target>::type v(target);
+ body.accept(v);
+ return v.target;
+}
+
+}} // namespace qpid::framing
+
+
+#endif /*!QPID_FRAMING_INVOKEVISITOR_H*/
+
+}} // namespace qpid::framing
+
+
+
+#endif /*!QPID_FRAMING_TEMPLATEVISITOR_H*/
diff --git a/RC9/qpid/cpp/src/qpid/framing/TransferContent.cpp b/RC9/qpid/cpp/src/qpid/framing/TransferContent.cpp
new file mode 100644
index 0000000000..3fc54296fa
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/TransferContent.cpp
@@ -0,0 +1,102 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "TransferContent.h"
+
+namespace qpid {
+namespace framing {
+
+TransferContent::TransferContent(const std::string& data, const std::string& key) {
+ setData(data);
+ if (!key.empty()) getDeliveryProperties().setRoutingKey(key);
+}
+
+
+AMQHeaderBody TransferContent::getHeader() const
+{
+ return header;
+}
+
+const std::string& TransferContent::getData() const {
+ return data;
+}
+
+std::string& TransferContent::getData() {
+ return data;
+}
+
+void TransferContent::setData(const std::string& _data)
+{
+ data = _data;
+ header.get<MessageProperties>(true)->setContentLength(data.size());
+}
+
+void TransferContent::appendData(const std::string& _data)
+{
+ data += _data;
+ header.get<MessageProperties>(true)->setContentLength(data.size());
+}
+
+MessageProperties& TransferContent::getMessageProperties()
+{
+ return *header.get<MessageProperties>(true);
+}
+
+DeliveryProperties& TransferContent::getDeliveryProperties()
+{
+ return *header.get<DeliveryProperties>(true);
+}
+
+void TransferContent::populate(const FrameSet& frameset)
+{
+ const AMQHeaderBody* h = frameset.getHeaders();
+ if (h) {
+ header = *h;
+ }
+ frameset.getContent(data);
+}
+
+const MessageProperties& TransferContent::getMessageProperties() const
+{
+ const MessageProperties* props = header.get<MessageProperties>();
+ if (!props) throw Exception("No message properties.");
+ return *props;
+}
+
+const DeliveryProperties& TransferContent::getDeliveryProperties() const
+{
+ const DeliveryProperties* props = header.get<DeliveryProperties>();
+ if (!props) throw Exception("No message properties.");
+ return *props;
+}
+
+bool TransferContent::hasMessageProperties() const
+{
+ return header.get<MessageProperties>();
+}
+
+bool TransferContent::hasDeliveryProperties() const
+{
+ return header.get<DeliveryProperties>();
+}
+
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/framing/TransferContent.h b/RC9/qpid/cpp/src/qpid/framing/TransferContent.h
new file mode 100644
index 0000000000..e3f6666fa4
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/TransferContent.h
@@ -0,0 +1,63 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _TransferContent_
+#define _TransferContent_
+
+#include "FrameSet.h"
+#include "MethodContent.h"
+#include "qpid/Exception.h"
+#include "qpid/framing/MessageProperties.h"
+#include "qpid/framing/DeliveryProperties.h"
+
+namespace qpid {
+namespace framing {
+
+/** Message content */
+class TransferContent : public MethodContent
+{
+ AMQHeaderBody header;
+ std::string data;
+public:
+ TransferContent(const std::string& data = std::string(), const std::string& key=std::string());
+
+ ///@internal
+ AMQHeaderBody getHeader() const;
+
+ void setData(const std::string&);
+ const std::string& getData() const;
+ std::string& getData();
+
+ void appendData(const std::string&);
+
+ bool hasMessageProperties() const;
+ MessageProperties& getMessageProperties();
+ const MessageProperties& getMessageProperties() const;
+
+ bool hasDeliveryProperties() const;
+ DeliveryProperties& getDeliveryProperties();
+ const DeliveryProperties& getDeliveryProperties() const;
+
+ ///@internal
+ void populate(const FrameSet& frameset);
+};
+
+}}
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/framing/TypeFilter.h b/RC9/qpid/cpp/src/qpid/framing/TypeFilter.h
new file mode 100644
index 0000000000..d1c42de583
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/TypeFilter.h
@@ -0,0 +1,51 @@
+#ifndef QPID_FRAMING_TYPEFILTER_H
+#define QPID_FRAMING_TYPEFILTER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <string>
+#include "qpid/framing/amqp_framing.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/FrameHandler.h"
+
+namespace qpid {
+namespace framing {
+
+/**
+ * Predicate that selects frames by type
+ */
+template <uint8_t Type>
+struct TypeFilter {
+ bool operator()(const AMQFrame& f) const {
+ return f.getBody()->type() == Type;
+ }
+};
+
+template <uint8_t T1, uint8_t T2>
+struct TypeFilter2 {
+ bool operator()(const AMQFrame& f) const {
+ return f.getBody()->type() == T1 || f.getBody()->type() == T2;
+ }
+};
+
+}} // namespace qpid::framing
+
+#endif /*!QPID_FRAMING_TYPEFILTER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/framing/Uuid.cpp b/RC9/qpid/cpp/src/qpid/framing/Uuid.cpp
new file mode 100644
index 0000000000..fbbaac1cf5
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/Uuid.cpp
@@ -0,0 +1,61 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "Uuid.h"
+#include "qpid/Exception.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/framing/reply_exceptions.h"
+
+namespace qpid {
+namespace framing {
+
+using namespace std;
+
+static const size_t UNPARSED_SIZE=36;
+
+void Uuid::encode(Buffer& buf) const {
+ buf.putRawData(data(), size());
+}
+
+void Uuid::decode(Buffer& buf) {
+ if (buf.available() < size())
+ throw IllegalArgumentException(QPID_MSG("Not enough data for UUID."));
+ buf.getRawData(c_array(), size());
+}
+
+ostream& operator<<(ostream& out, Uuid uuid) {
+ char unparsed[UNPARSED_SIZE + 1];
+ uuid_unparse(uuid.data(), unparsed);
+ return out << unparsed;
+}
+
+istream& operator>>(istream& in, Uuid& uuid) {
+ char unparsed[UNPARSED_SIZE + 1] = {0};
+ in.get(unparsed, sizeof(unparsed));
+ if (uuid_parse(unparsed, uuid.c_array()) != 0)
+ in.setstate(ios::failbit);
+ return in;
+}
+
+std::string Uuid::str() const {
+ std::ostringstream os;
+ os << *this;
+ return os.str();
+}
+
+}} // namespace qpid::framing
diff --git a/RC9/qpid/cpp/src/qpid/framing/Uuid.h b/RC9/qpid/cpp/src/qpid/framing/Uuid.h
new file mode 100644
index 0000000000..2fcbb5a261
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/Uuid.h
@@ -0,0 +1,88 @@
+#ifndef QPID_FRAMING_UUID_H
+#define QPID_FRAMING_UUID_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/sys/uuid.h"
+
+#include <boost/array.hpp>
+
+#include <ostream>
+#include <istream>
+
+namespace qpid {
+namespace framing {
+
+class Buffer;
+
+/**
+ * A UUID is represented as a boost::array of 16 bytes.
+ *
+ * Full value semantics, operators ==, < etc. are provided by
+ * boost::array so Uuid can be the key type in a map etc.
+ */
+struct Uuid : public boost::array<uint8_t, 16> {
+ /** If unique is true, generate a unique ID else a null ID. */
+ Uuid(bool unique=false) { if (unique) generate(); else clear(); }
+
+ /** Copy from 16 bytes of data. */
+ Uuid(uint8_t* data) { assign(data); }
+
+ /** Copy from 16 bytes of data. */
+ void assign(uint8_t* data) {
+ uuid_copy(c_array(), data);
+ }
+
+ /** Set to a new unique identifier. */
+ void generate() { uuid_generate(c_array()); }
+
+ /** Set to all zeros. */
+ void clear() { uuid_clear(c_array()); }
+
+ /** Test for null (all zeros). */
+ bool isNull() {
+ return uuid_is_null(data());
+ }
+
+ // Default op= and copy ctor are fine.
+ // boost::array gives us ==, < etc.
+
+ void encode(framing::Buffer& buf) const;
+ void decode(framing::Buffer& buf);
+ uint32_t encodedSize() const { return size(); }
+
+ /** String value in format 1b4e28ba-2fa1-11d2-883f-b9a761bde3fb. */
+ std::string str() const;
+
+ template <class S> void serialize(S& s) {
+ s.raw(begin(), size());
+ }
+};
+
+/** Print in format 1b4e28ba-2fa1-11d2-883f-b9a761bde3fb. */
+std::ostream& operator<<(std::ostream&, Uuid);
+
+/** Read from format 1b4e28ba-2fa1-11d2-883f-b9a761bde3fb. */
+std::istream& operator>>(std::istream&, Uuid&);
+
+}} // namespace qpid::framing
+
+
+
+#endif /*!QPID_FRAMING_UUID_H*/
diff --git a/RC9/qpid/cpp/src/qpid/framing/Visitor.h b/RC9/qpid/cpp/src/qpid/framing/Visitor.h
new file mode 100644
index 0000000000..759ee65914
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/Visitor.h
@@ -0,0 +1,92 @@
+#ifndef QPID_FRAMING_VISITOR_H
+#define QPID_FRAMING_VISITOR_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <boost/mpl/vector.hpp>
+#include <boost/type_traits/remove_reference.hpp>
+#include <boost/preprocessor/seq/for_each.hpp>
+
+namespace qpid {
+namespace framing {
+
+/** @file Generic visitor pattern. */
+
+/** visit() interface for type T (optional return type R, default is void.)
+ * To create a visitor for a set of types T1, T2 ... do this:
+ * struct MyVisitor : public Visit<T1>, public Visit<T2> ... {};
+ *@param T Type to visit. This must be forward declared, and need not be defined.
+ */
+template <class T, class R=void> struct Visit {
+ typedef R ReturnType;
+ typedef T VisitType;
+
+ virtual ~Visit() {}
+ virtual R visit(T&) = 0;
+};
+
+
+#define QPID_VISITOR_DECL(_1,_2,T) class T;
+
+#define QPID_VISITOR_BASE(_1,_2,T) , public ::qpid::framing::Visit<T>
+
+/** Convenience macro to generate a visitor interface.
+ * QPID_VISITOR(MyVisitor,(A)(B)(C)); is equivalent to:
+ * @code
+ * class A; class B; class C;
+ * class MyVisitor : public Visit<A> , public Visit<B> , public Visit<C> {};
+ * @endcode
+ * @param visitor name of the generated visitor class.
+ * @param bases a sequence of visitable types in the form (T1)(T2)...
+ * Any parenthesized notations are due to quirks of the preprocesser.
+ */
+#define QPID_VISITOR(visitor,types) \
+ BOOST_PP_SEQ_FOR_EACH(QPID_VISITOR_DECL, _, types) \
+ class visitor : public ::qpid::framing::Visit<BOOST_PP_SEQ_HEAD(types)> \
+ BOOST_PP_SEQ_FOR_EACH(QPID_VISITOR_BASE, _, BOOST_PP_SEQ_TAIL(types)) \
+ {}
+
+/** The root class for the hierarchy of objects visitable by Visitor V.
+ * Defines virtual accept().
+ */
+template <class V, class R=void>
+struct VisitableRoot {
+ typedef V VisitorType;
+ typedef R ReturnType;
+ virtual ~VisitableRoot() {}
+ virtual R accept(V& v) = 0;
+};
+
+/** The base class for concrete visitable classes.
+ * Implements accept().
+ * @param T type of visitable class (CRTP).
+ * @param Base base class to inherit from.
+ */
+template <class T, class Base>
+struct Visitable : public Base {
+ void accept(typename Base::VisitorType& v) {
+ static_cast<Visit<T>& >(v).visit(static_cast<T&>(*this));
+ }
+};
+
+}} // namespace qpid::framing
+
+#endif /*!QPID_FRAMING_VISITOR_H*/
diff --git a/RC9/qpid/cpp/src/qpid/framing/amqp_framing.h b/RC9/qpid/cpp/src/qpid/framing/amqp_framing.h
new file mode 100644
index 0000000000..4e4747c3f4
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/amqp_framing.h
@@ -0,0 +1,32 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "amqp_types.h"
+#include "AMQFrame.h"
+#include "AMQBody.h"
+#include "BodyHandler.h"
+#include "AMQMethodBody.h"
+#include "AMQHeaderBody.h"
+#include "AMQContentBody.h"
+#include "AMQHeartbeatBody.h"
+#include "InputHandler.h"
+#include "OutputHandler.h"
+#include "ProtocolInitiation.h"
+#include "ProtocolVersion.h"
diff --git a/RC9/qpid/cpp/src/qpid/framing/amqp_types.h b/RC9/qpid/cpp/src/qpid/framing/amqp_types.h
new file mode 100644
index 0000000000..97b889a7ca
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/amqp_types.h
@@ -0,0 +1,63 @@
+#ifndef AMQP_TYPES_H
+#define AMQP_TYPES_H
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/** \file
+ * Definitions and forward declarations of all types used
+ * in AMQP messages.
+ */
+
+#include "qpid/sys/IntegerTypes.h"
+#include <string>
+
+namespace qpid {
+namespace framing {
+
+using std::string;
+typedef uint8_t FrameType;
+typedef uint16_t ChannelId;
+typedef uint32_t BatchOffset;
+typedef uint8_t ClassId;
+typedef uint8_t MethodId;
+typedef uint16_t ReplyCode;
+
+// Types represented by classes.
+class Content;
+class FieldTable;
+class SequenceNumberSet;
+struct Uuid;
+
+// Useful constants
+
+/** Maximum channel ID used by broker. Reserve high bit for internal use.*/
+const ChannelId CHANNEL_MAX=(ChannelId(~1))>>1;
+const ChannelId CHANNEL_HIGH_BIT= ChannelId(~CHANNEL_MAX);
+
+// Forward declare class types
+class FramingContent;
+class FieldTable;
+class SequenceNumberSet;
+class SequenceSet;
+struct Uuid;
+
+}} // namespace qpid::framing
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/framing/amqp_types_full.h b/RC9/qpid/cpp/src/qpid/framing/amqp_types_full.h
new file mode 100644
index 0000000000..d0aaf28cb4
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/amqp_types_full.h
@@ -0,0 +1,38 @@
+#ifndef _framing_amqp_types_decl_h
+#define _framing_amqp_types_decl_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/** \file
+ * Definitions and full declarations of all types used
+ * in AMQP messages.
+ *
+ * It's better to include amqp_types.h in another header instead of this file
+ * unless the header actually needs the full declarations. Including
+ * full declarations when forward declarations would increase compile
+ * times.
+ */
+
+#include "amqp_types.h"
+#include "Array.h"
+#include "FieldTable.h"
+#include "SequenceSet.h"
+#include "Uuid.h"
+
+#endif /*!_framing_amqp_types_decl_h*/
diff --git a/RC9/qpid/cpp/src/qpid/framing/frame_functors.h b/RC9/qpid/cpp/src/qpid/framing/frame_functors.h
new file mode 100644
index 0000000000..d2064d6a57
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/frame_functors.h
@@ -0,0 +1,116 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <string>
+#include <ostream>
+#include <iostream>
+#include "qpid/framing/amqp_framing.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/Buffer.h"
+
+#ifndef _frame_functors_
+#define _frame_functors_
+
+namespace qpid {
+namespace framing {
+
+class SumFrameSize
+{
+ uint64_t size;
+public:
+ SumFrameSize() : size(0) {}
+ void operator()(const AMQFrame& f) { size += f.encodedSize(); }
+ uint64_t getSize() { return size; }
+};
+
+class SumBodySize
+{
+ uint64_t size;
+public:
+ SumBodySize() : size(0) {}
+ void operator()(const AMQFrame& f) { size += f.getBody()->encodedSize(); }
+ uint64_t getSize() { return size; }
+};
+
+class Count
+{
+ uint count;
+public:
+ Count() : count(0) {}
+ void operator()(const AMQFrame&) { count++; }
+ uint getCount() { return count; }
+};
+
+class EncodeFrame
+{
+ Buffer& buffer;
+public:
+ EncodeFrame(Buffer& b) : buffer(b) {}
+ void operator()(const AMQFrame& f) { f.encode(buffer); }
+};
+
+class EncodeBody
+{
+ Buffer& buffer;
+public:
+ EncodeBody(Buffer& b) : buffer(b) {}
+ void operator()(const AMQFrame& f) { f.getBody()->encode(buffer); }
+};
+
+/**
+ * Sends to the specified handler a copy of the frame it is applied to.
+ */
+class Relay
+{
+ FrameHandler& handler;
+
+public:
+ Relay(FrameHandler& h) : handler(h) {}
+
+ void operator()(const AMQFrame& f)
+ {
+ AMQFrame copy(f);
+ handler.handle(copy);
+ }
+};
+
+class Print
+{
+ std::ostream& out;
+public:
+ Print(std::ostream& o) : out(o) {}
+
+ void operator()(const AMQFrame& f)
+ {
+ out << f << std::endl;
+ }
+};
+
+class MarkLastSegment
+{
+public:
+ void operator()(AMQFrame& f) const { f.setEof(true); }
+};
+
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/framing/variant.h b/RC9/qpid/cpp/src/qpid/framing/variant.h
new file mode 100644
index 0000000000..8e13063385
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/framing/variant.h
@@ -0,0 +1,91 @@
+#ifndef QPID_FRAMING_VARIANT_H
+#define QPID_FRAMING_VARIANT_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/**@file Tools for using boost::variant. */
+
+
+#include <boost/variant.hpp>
+
+namespace qpid {
+namespace framing {
+class Buffer;
+
+/** boost::static_visitor that throws an exception if variant contains a blank.
+ * Subclasses need to have a using() declaration, which can be generated
+ * with QPID_USING_NOBLANK(R)
+ */
+template <class R=void>
+struct NoBlankVisitor : public boost::static_visitor<R> {
+ R foundBlank() const {
+ assert(0);
+ throw Exception(QPID_MSG("Invalid variant value."));
+ }
+ R operator()(const boost::blank&) const { return foundBlank(); }
+ R operator()(boost::blank&) const { return foundBlank(); }
+};
+
+
+}} // qpid::framing
+
+
+/** Generate a using statement, needed in visitors inheriting NoBlankVisitor
+ * @param R return type.
+ */
+#define QPID_USING_NOBLANK(R) using ::qpid::framing::NoBlankVisitor<R>::operator()
+
+namespace qpid {
+namespace framing {
+
+/** Convert the variant value to type R. */
+template <class R> struct ConvertVisitor : public NoBlankVisitor<R> {
+ QPID_USING_NOBLANK(R);
+ template <class T> R operator()(T& t) const { return t; }
+};
+
+/** Convert the address of variant value to type R. */
+template <class R> struct AddressVisitor : public NoBlankVisitor<R> {
+ QPID_USING_NOBLANK(R);
+ template <class T> R operator()(T& t) const { return &t; }
+};
+
+/** Apply a visitor to the nested variant.*/
+template<class V>
+struct ApplyVisitor : public NoBlankVisitor<typename V::result_type> {
+ QPID_USING_NOBLANK(typename V::result_type);
+ const V& visitor;
+ ApplyVisitor(const V& v) : visitor(v) {}
+ template <class T> typename V::result_type operator()(T& t) const {
+ return boost::apply_visitor(visitor, t);
+ }
+};
+
+/** Convenience function to construct and apply an ApplyVisitor */
+template <class Visitor, class Visitable>
+typename Visitor::result_type applyApplyVisitor(const Visitor& visitor, Visitable& visitable) {
+ return boost::apply_visitor(ApplyVisitor<Visitor>(visitor), visitable);
+}
+
+}} // namespace qpid::framing
+
+
+#endif /*!QPID_FRAMING_VARIANT_H*/
diff --git a/RC9/qpid/cpp/src/qpid/log/Helpers.h b/RC9/qpid/cpp/src/qpid/log/Helpers.h
new file mode 100644
index 0000000000..82ef8244be
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/log/Helpers.h
@@ -0,0 +1,79 @@
+#ifndef QPID_LOG_HELPERS_H
+#define QPID_LOG_HELPERS_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <boost/range.hpp>
+
+#include <ostream>
+
+namespace qpid {
+namespace log {
+
+/** @file Helper classes for logging complex types */
+
+/// @internal
+template <class Range>
+struct ListFormatter {
+ typedef typename boost::range_const_iterator<Range>::type Iterator;
+ boost::iterator_range<Iterator> range;
+ const char* separator;
+
+ ListFormatter(const Range& r, const char* s=", ") : range(r), separator(s) {}
+};
+
+/// @internal
+template <class Range>
+std::ostream& operator<<(std::ostream& out, const ListFormatter<Range>& sl) {
+ typename ListFormatter<Range>::Iterator i = sl.range.begin();
+ if (i != sl.range.end()) out << *(i++);
+ while (i != sl.range.end()) out << sl.separator << *(i++);
+ return out;
+}
+
+/** Return a formatting object with operator <<
+ * to stream range as a separated list.
+ *@param range: a range - all standard containers are ranges,
+ * as is a pair of iterators.
+ *@param separator: printed between elements, default ", "
+ */
+template <class Range>
+ListFormatter<Range> formatList(const Range& range, const char* separator=", ") {
+ return ListFormatter<Range>(range, separator);
+}
+
+/** Return a formatting object with operator <<
+ * to stream the range defined by iterators [begin, end)
+ * as a separated list.
+ *@param begin, end: Beginning and end of range.
+ *@param separator: printed between elements, default ", "
+ */
+template <class U, class V>
+ListFormatter<std::pair<U,V> > formatList(U begin, V end, const char* separator=", ") {
+ return formatList(std::make_pair(begin,end), separator);
+}
+
+
+}} // namespace qpid::log
+
+
+
+#endif /*!QPID_LOG_HELPERS_H*/
diff --git a/RC9/qpid/cpp/src/qpid/log/Logger.cpp b/RC9/qpid/cpp/src/qpid/log/Logger.cpp
new file mode 100644
index 0000000000..07e4245399
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/log/Logger.cpp
@@ -0,0 +1,168 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "Logger.h"
+#include "Options.h"
+#include "SinkOptions.h"
+#include "qpid/memory.h"
+#include "qpid/sys/Thread.h"
+#include <boost/pool/detail/singleton.hpp>
+#include <boost/bind.hpp>
+#include <boost/function.hpp>
+#include <algorithm>
+#include <sstream>
+#include <iomanip>
+#include <stdexcept>
+#include <time.h>
+
+
+namespace qpid {
+namespace log {
+
+using namespace std;
+
+typedef sys::Mutex::ScopedLock ScopedLock;
+
+inline void Logger::enable_unlocked(Statement* s) {
+ s->enabled=selector.isEnabled(s->level, s->function);
+}
+
+Logger& Logger::instance() {
+ return boost::details::pool::singleton_default<Logger>::instance();
+}
+
+Logger::Logger() : flags(0) {
+ // Initialize myself from env variables so all programs
+ // (e.g. tests) can use logging even if they don't parse
+ // command line args.
+ Options opts("");
+ opts.parse(0, 0);
+ configure(opts);
+}
+
+Logger::~Logger() {}
+
+void Logger::select(const Selector& s) {
+ ScopedLock l(lock);
+ selector=s;
+ std::for_each(statements.begin(), statements.end(),
+ boost::bind(&Logger::enable_unlocked, this, _1));
+}
+
+Logger::Output::Output() {}
+Logger::Output::~Output() {}
+
+void Logger::log(const Statement& s, const std::string& msg) {
+ // Format the message outside the lock.
+ std::ostringstream os;
+ if (!prefix.empty())
+ os << prefix << ": ";
+ if (flags&TIME)
+ {
+ const char * month_abbrevs[] = { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec" };
+ time_t rawtime;
+ struct tm * timeinfo;
+
+ time ( & rawtime );
+ timeinfo = localtime ( &rawtime );
+ char time_string[100];
+ sprintf ( time_string,
+ "%d-%s-%02d %02d:%02d:%02d",
+ 1900 + timeinfo->tm_year,
+ month_abbrevs[timeinfo->tm_mon],
+ timeinfo->tm_mday,
+ timeinfo->tm_hour,
+ timeinfo->tm_min,
+ timeinfo->tm_sec
+ );
+ os << time_string << " ";
+ }
+ if (flags&LEVEL)
+ os << LevelTraits::name(s.level) << " ";
+ if (flags&THREAD)
+ os << "[0x" << hex << qpid::sys::Thread::logId() << "] ";
+ if (flags&FILE)
+ os << s.file << ":";
+ if (flags&LINE)
+ os << dec << s.line << ":";
+ if (flags&FUNCTION)
+ os << s.function << ":";
+ if (flags & (FILE|LINE|FUNCTION))
+ os << " ";
+ os << msg << endl;
+ std::string formatted=os.str();
+ {
+ ScopedLock l(lock);
+ std::for_each(outputs.begin(), outputs.end(),
+ boost::bind(&Output::log, _1, s, formatted));
+ }
+}
+
+void Logger::output(std::auto_ptr<Output> out) {
+ ScopedLock l(lock);
+ outputs.push_back(out.release());
+}
+
+void Logger::clear() {
+ select(Selector()); // locked
+ format(0); // locked
+ ScopedLock l(lock);
+ outputs.clear();
+}
+
+void Logger::format(int formatFlags) {
+ ScopedLock l(lock);
+ flags=formatFlags;
+}
+
+static int bitIf(bool test, int bit) {
+ return test ? bit : 0;
+}
+
+int Logger::format(const Options& opts) {
+ int flags=
+ bitIf(opts.level, LEVEL) |
+ bitIf(opts.time, TIME) |
+ bitIf(opts.source, (FILE|LINE)) |
+ bitIf(opts.function, FUNCTION) |
+ bitIf(opts.thread, THREAD);
+ format(flags);
+ return flags;
+}
+
+void Logger::add(Statement& s) {
+ ScopedLock l(lock);
+ enable_unlocked(&s);
+ statements.insert(&s);
+}
+
+void Logger::configure(const Options& opts) {
+ options = opts;
+ clear();
+ Options o(opts);
+ if (o.trace)
+ o.selectors.push_back("trace+");
+ format(o);
+ select(Selector(o));
+ setPrefix(opts.prefix);
+ options.sinkOptions->setup(this);
+}
+
+void Logger::setPrefix(const std::string& p) { prefix = p; }
+
+}} // namespace qpid::log
diff --git a/RC9/qpid/cpp/src/qpid/log/Logger.h b/RC9/qpid/cpp/src/qpid/log/Logger.h
new file mode 100644
index 0000000000..539c1c851b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/log/Logger.h
@@ -0,0 +1,113 @@
+#ifndef QPID_LOG_LOGGER_H
+#define QPID_LOG_LOGGER_H
+
+/*
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "Selector.h"
+#include "Options.h"
+#include "qpid/sys/Mutex.h"
+#include <boost/ptr_container/ptr_vector.hpp>
+#include <boost/noncopyable.hpp>
+#include <set>
+
+namespace qpid {
+namespace log {
+
+/**
+ * Central logging agent.
+ *
+ * Thread safe, singleton.
+ *
+ * The Logger provides all needed functionality for selecting and
+ * formatting logging output. The actual outputting of log records
+ * is handled by Logger::Output-derived classes instantiated by the
+ * platform's sink-related options.
+ */
+class Logger : private boost::noncopyable {
+ public:
+ /** Flags indicating what to include in the log output */
+ enum FormatFlag { FILE=1, LINE=2, FUNCTION=4, LEVEL=8, TIME=16, THREAD=32};
+
+ /**
+ * Logging output sink.
+ *
+ * The Output sink provides an interface to direct logging output to.
+ * Logging sinks are primarily platform-specific as provided for on
+ * each platform.
+ *
+ * Implementations of Output must be thread safe.
+ */
+ class Output {
+ public:
+ Output();
+ virtual ~Output();
+ /** Receives the statemnt of origin and formatted message to log. */
+ virtual void log(const Statement&, const std::string&) =0;
+ };
+
+ static Logger& instance();
+
+ Logger();
+ ~Logger();
+
+ /** Select the messages to be logged. */
+ void select(const Selector& s);
+
+ /** Set the formatting flags, bitwise OR of FormatFlag values. */
+ void format(int formatFlags);
+
+ /** Set format flags from options object.
+ *@returns computed flags.
+ */
+ int format(const Options&);
+
+ /** Configure logger from Options */
+ void configure(const Options& o);
+
+ /** Add a statement. */
+ void add(Statement& s);
+
+ /** Log a message. */
+ void log(const Statement&, const std::string&);
+
+ /** Add an output destination for messages */
+ void output(std::auto_ptr<Output> out);
+
+ /** Set a prefix for all messages */
+ void setPrefix(const std::string& prefix);
+
+ /** Reset the logger. */
+ void clear();
+
+ /** Get the options used to configure the logger. */
+ const Options& getOptions() const { return options; }
+
+
+ private:
+ typedef boost::ptr_vector<Output> Outputs;
+ typedef std::set<Statement*> Statements;
+
+ sys::Mutex lock;
+ inline void enable_unlocked(Statement* s);
+
+ Statements statements;
+ Outputs outputs;
+ Selector selector;
+ int flags;
+ std::string prefix;
+ Options options;
+};
+
+}} // namespace qpid::log
+
+
+#endif /*!QPID_LOG_LOGGER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/log/Options.cpp b/RC9/qpid/cpp/src/qpid/log/Options.cpp
new file mode 100644
index 0000000000..a33da6fd8f
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/log/Options.cpp
@@ -0,0 +1,107 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "Options.h"
+#include "SinkOptions.h"
+#include "Statement.h"
+#include "qpid/Options.h"
+#include <map>
+#include <string>
+#include <algorithm>
+
+namespace qpid {
+namespace log {
+
+using namespace std;
+
+Options::Options(const std::string& argv0_, const std::string& name_) :
+ qpid::Options(name_),
+ argv0(argv0_),
+ name(name_),
+ time(true),
+ level(true),
+ thread(false),
+ source(false),
+ function(false),
+ trace(false),
+ sinkOptions (SinkOptions::create(argv0_))
+{
+ selectors.push_back("notice+");
+
+ ostringstream levels;
+ levels << LevelTraits::name(Level(0));
+ for (int i = 1; i < LevelTraits::COUNT; ++i)
+ levels << " " << LevelTraits::name(Level(i));
+
+ addOptions()
+ ("trace,t", optValue(trace), "Enables all logging" )
+ ("log-enable", optValue(selectors, "RULE"),
+ ("Enables logging for selected levels and components. "
+ "RULE is in the form 'LEVEL[+][:PATTERN]' "
+ "Levels are one of: \n\t "+levels.str()+"\n"
+ "For example:\n"
+ "\t'--log-enable warning+' "
+ "logs all warning, error and critical messages.\n"
+ "\t'--log-enable debug:framing' "
+ "logs debug messages from the framing namespace. "
+ "This option can be used multiple times").c_str())
+ ("log-time", optValue(time, "yes|no"), "Include time in log messages")
+ ("log-level", optValue(level,"yes|no"), "Include severity level in log messages")
+ ("log-source", optValue(source,"yes|no"), "Include source file:line in log messages")
+ ("log-thread", optValue(thread,"yes|no"), "Include thread ID in log messages")
+ ("log-function", optValue(function,"yes|no"), "Include function signature in log messages")
+ ("log-prefix", optValue(prefix,"STRING"), "Prefix to append to all log messages")
+ ;
+ add(*sinkOptions);
+}
+
+Options::Options(const Options &o) :
+ qpid::Options(o.name),
+ argv0(o.argv0),
+ name(o.name),
+ selectors(o.selectors),
+ time(o.time),
+ level(o.level),
+ thread(o.thread),
+ source(o.source),
+ function(o.function),
+ trace(o.trace),
+ prefix(o.prefix),
+ sinkOptions (SinkOptions::create(o.argv0))
+{
+ *sinkOptions = *o.sinkOptions;
+}
+
+Options& Options::operator=(const Options& x) {
+ if (this != &x) {
+ argv0 = x.argv0;
+ name = x.name;
+ selectors = x.selectors;
+ time = x.time;
+ level= x.level;
+ thread = x.thread;
+ source = x.source;
+ function = x.function;
+ trace = x.trace;
+ prefix = x.prefix;
+ *sinkOptions = *x.sinkOptions;
+ }
+ return *this;
+}
+
+}} // namespace qpid::log
diff --git a/RC9/qpid/cpp/src/qpid/log/Options.h b/RC9/qpid/cpp/src/qpid/log/Options.h
new file mode 100644
index 0000000000..8a3c352d14
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/log/Options.h
@@ -0,0 +1,49 @@
+#ifndef QPID_LOG_OPTIONS_H
+#define QPID_LOG_OPTIONS_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "qpid/Options.h"
+#include "SinkOptions.h"
+#include <iosfwd>
+#include <memory>
+
+namespace qpid {
+namespace log {
+
+/** Logging options for config parser. */
+struct Options : public qpid::Options {
+ /** Pass argv[0] for use in syslog output */
+ Options(const std::string& argv0_=std::string(),
+ const std::string& name_="Logging options");
+ Options(const Options &);
+
+ Options& operator=(const Options&);
+
+ std::string argv0;
+ std::string name;
+ std::vector<std::string> selectors;
+ bool time, level, thread, source, function;
+ bool trace;
+ std::string prefix;
+ std::auto_ptr<SinkOptions> sinkOptions;
+};
+
+}} // namespace qpid::log
+
+#endif /*!QPID_LOG_OPTIONS_H*/
diff --git a/RC9/qpid/cpp/src/qpid/log/OstreamOutput.cpp b/RC9/qpid/cpp/src/qpid/log/OstreamOutput.cpp
new file mode 100644
index 0000000000..c96a311a4e
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/log/OstreamOutput.cpp
@@ -0,0 +1,41 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "OstreamOutput.h"
+#include <stdexcept>
+
+using namespace std;
+
+namespace qpid {
+namespace log {
+
+OstreamOutput::OstreamOutput(std::ostream& o) : out(&o) {}
+
+OstreamOutput::OstreamOutput(const std::string& file)
+ : out(new ofstream(file.c_str(), ios_base::out | ios_base::app)),
+ mine(out)
+{
+ if (!out->good())
+ throw std::runtime_error("Can't open log file: "+file);
+}
+
+void OstreamOutput::log(const Statement&, const std::string& m) {
+ *out << m << flush;
+}
+
+}} // namespace qpid::log
diff --git a/RC9/qpid/cpp/src/qpid/log/OstreamOutput.h b/RC9/qpid/cpp/src/qpid/log/OstreamOutput.h
new file mode 100644
index 0000000000..8bbfc8c38b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/log/OstreamOutput.h
@@ -0,0 +1,41 @@
+#ifndef QPID_LOG_OSTREAMOUTPUT_H
+#define QPID_LOG_OSTREAMOUTPUT_H
+
+/*
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "Logger.h"
+#include <boost/scoped_ptr.hpp>
+#include <fstream>
+#include <ostream>
+
+namespace qpid {
+namespace log {
+
+/**
+ * OstreamOutput is a reusable logging sink that directs logging to a C++
+ * ostream.
+ */
+class OstreamOutput : public qpid::log::Logger::Output {
+public:
+ OstreamOutput(std::ostream& o);
+ OstreamOutput(const std::string& file);
+
+ virtual void log(const Statement&, const std::string& m);
+
+private:
+ std::ostream* out;
+ boost::scoped_ptr<std::ostream> mine;
+};
+
+}} // namespace qpid::log
+
+#endif /*!QPID_LOG_OSTREAMOUTPUT_H*/
diff --git a/RC9/qpid/cpp/src/qpid/log/Selector.cpp b/RC9/qpid/cpp/src/qpid/log/Selector.cpp
new file mode 100644
index 0000000000..4d1c5b6e0c
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/log/Selector.cpp
@@ -0,0 +1,67 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "Selector.h"
+#include "Options.h"
+#include <boost/bind.hpp>
+#include <algorithm>
+
+namespace qpid {
+namespace log {
+
+using namespace std;
+
+void Selector::enable(const string& enableStr) {
+ string level, pattern;
+ size_t c=enableStr.find(':');
+ if (c==string::npos) {
+ level=enableStr;
+ }
+ else {
+ level=enableStr.substr(0,c);
+ pattern=enableStr.substr(c+1);
+ }
+ if (!level.empty() && level[level.size()-1]=='+') {
+ for (int i = LevelTraits::level(level.substr(0,level.size()-1));
+ i < LevelTraits::COUNT;
+ ++i)
+ enable(Level(i), pattern);
+ }
+ else {
+ enable(LevelTraits::level(level), pattern);
+ }
+}
+
+Selector::Selector(const Options& opt){
+ for_each(opt.selectors.begin(), opt.selectors.end(),
+ boost::bind(&Selector::enable, this, _1));
+}
+
+bool Selector::isEnabled(Level level, const char* function) {
+ const char* functionEnd = function+::strlen(function);
+ for (std::vector<std::string>::iterator i=substrings[level].begin();
+ i != substrings[level].end();
+ ++i)
+ {
+ if (std::search(function, functionEnd, i->begin(), i->end()) != functionEnd)
+ return true;
+ }
+ return false;
+}
+
+}} // namespace qpid::log
diff --git a/RC9/qpid/cpp/src/qpid/log/Selector.h b/RC9/qpid/cpp/src/qpid/log/Selector.h
new file mode 100644
index 0000000000..705abfeb5d
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/log/Selector.h
@@ -0,0 +1,70 @@
+#ifndef SELECTOR_H
+#define SELECTOR_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "Statement.h"
+#include <vector>
+
+namespace qpid {
+namespace log {
+struct Options;
+
+/**
+ * A selector identifies the set of log messages to enable.
+ *
+ * Thread object unsafe, pass-by-value type.
+ */
+class Selector {
+ public:
+ /** Empty selector selects nothing */
+ Selector() {}
+
+ /** Set selector from Options */
+ Selector(const Options&);
+
+ /** Equavlient to: Selector s; s.enable(l, s) */
+ Selector(Level l, const std::string& s=std::string()) {
+ enable(l,s);
+ }
+
+ Selector(const std::string& enableStr) { enable(enableStr); }
+ /**
+ * Enable messages with level in levels where the file
+ * name contains substring. Empty string matches all.
+ */
+ void enable(Level level, const std::string& substring=std::string()) {
+ substrings[level].push_back(substring);
+ }
+
+ /** Enable based on a 'level[+]:file' string */
+ void enable(const std::string& enableStr);
+
+ /** True if level is enabled for file. */
+ bool isEnabled(Level level, const char* function);
+
+ private:
+ std::vector<std::string> substrings[LevelTraits::COUNT];
+};
+
+
+}} // namespace qpid::log
+
+
+#endif /*!SELECTOR_H*/
diff --git a/RC9/qpid/cpp/src/qpid/log/SinkOptions.h b/RC9/qpid/cpp/src/qpid/log/SinkOptions.h
new file mode 100644
index 0000000000..7ec2cfbc17
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/log/SinkOptions.h
@@ -0,0 +1,64 @@
+#ifndef QPID_LOG_SINKOPTIONS_H
+#define QPID_LOG_SINKOPTIONS_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/Options.h"
+#include <string>
+
+namespace qpid {
+namespace log {
+
+class Logger;
+
+/**
+ * Logging sink options.
+ *
+ * Most logging sink options will be platform-specific, even if some are
+ * duplicated. The range of platforms to which this code may be ported
+ * can't be assumed to all have C++ iostreams or files. Thus, this class
+ * is primarily for implementing in a platform-specific way.
+ */
+struct SinkOptions : public qpid::Options {
+
+ // Create a platform's SinkOptions. Pass argv0 as the program name,
+ // useful for syslog-type logging.
+ static SinkOptions *create(const std::string& argv0=std::string());
+
+ SinkOptions(const std::string& name="Logging sink options")
+ : qpid::Options(name)
+ {}
+ virtual ~SinkOptions() {}
+
+ virtual SinkOptions& operator=(const SinkOptions&) = 0;
+
+ // This allows the caller to indicate that there's no normal outputs
+ // available. For example, when running as a daemon. In these cases, the
+ // platform's "syslog"-type output should replace the default stderr
+ // unless some other sink has been selected.
+ virtual void detached(void) = 0;
+
+ // The Logger acting on these options calls setup() to request any
+ // Sinks be set up and fed back to the logger.
+ virtual void setup(Logger *logger) = 0;
+};
+
+}} // namespace qpid::log
+
+#endif /*!QPID_LOG_OPTIONS_H*/
diff --git a/RC9/qpid/cpp/src/qpid/log/Statement.cpp b/RC9/qpid/cpp/src/qpid/log/Statement.cpp
new file mode 100644
index 0000000000..090a993e78
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/log/Statement.cpp
@@ -0,0 +1,83 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "Statement.h"
+#include "Logger.h"
+#include <boost/bind.hpp>
+#include <stdexcept>
+#include <algorithm>
+#include <ctype.h>
+
+namespace qpid {
+namespace log {
+
+namespace {
+using namespace std;
+
+struct NonPrint { bool operator()(unsigned char c) { return !isprint(c) && !isspace(c); } };
+
+const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+std::string quote(const std::string& str) {
+ NonPrint nonPrint;
+ size_t n = std::count_if(str.begin(), str.end(), nonPrint);
+ if (n==0) return str;
+ std::string ret;
+ ret.reserve(str.size()+2*n); // Avoid extra allocations.
+ for (string::const_iterator i = str.begin(); i != str.end(); ++i) {
+ if (nonPrint(*i)) {
+ ret.push_back('\\');
+ ret.push_back('x');
+ ret.push_back(hex[((*i) >> 4)&0xf]);
+ ret.push_back(hex[(*i) & 0xf]);
+ }
+ else ret.push_back(*i);
+ }
+ return ret;
+}
+
+}
+
+void Statement::log(const std::string& message) {
+ Logger::instance().log(*this, quote(message));
+}
+
+Statement::Initializer::Initializer(Statement& s) : statement(s) {
+ Logger::instance().add(s);
+}
+
+namespace {
+const char* names[LevelTraits::COUNT] = {
+ "trace", "debug", "info", "notice", "warning", "error", "critical"
+};
+
+} // namespace
+
+Level LevelTraits::level(const char* name) {
+ for (int i =0; i < LevelTraits::COUNT; ++i) {
+ if (strcmp(names[i], name)==0)
+ return Level(i);
+ }
+ throw std::runtime_error(std::string("Invalid log level name: ")+name);
+}
+
+const char* LevelTraits::name(Level l) {
+ return names[l];
+}
+
+}} // namespace qpid::log
diff --git a/RC9/qpid/cpp/src/qpid/log/Statement.h b/RC9/qpid/cpp/src/qpid/log/Statement.h
new file mode 100644
index 0000000000..3c67b04b20
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/log/Statement.h
@@ -0,0 +1,121 @@
+#ifndef STATEMENT_H
+#define STATEMENT_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/Msg.h"
+
+#include <boost/current_function.hpp>
+
+namespace qpid {
+namespace log {
+
+/** Debugging severity levels
+ * - trace: High-volume debugging messages.
+ * - debug: Debugging messages.
+ * - info: Informational messages.
+ * - notice: Normal but significant condition.
+ * - warning: Warn of a possible problem.
+ * - error: A definite error has occured.
+ * - critical: System in danger of severe failure.
+ */
+enum Level { trace, debug, info, notice, warning, error, critical };
+struct LevelTraits {
+ static const int COUNT=critical+1;
+
+ /** Get level from string name.
+ *@exception if name invalid.
+ */
+ static Level level(const char* name);
+
+ /** Get level from string name.
+ *@exception if name invalid.
+ */
+ static Level level(const std::string& name) {
+ return level(name.c_str());
+ }
+
+ /** String name of level */
+ static const char* name(Level);
+};
+
+/** POD struct representing a logging statement in source code. */
+struct Statement {
+ bool enabled;
+ const char* file;
+ int line;
+ const char* function;
+ Level level;
+
+ void log(const std::string& message);
+
+ struct Initializer {
+ Initializer(Statement& s);
+ Statement& statement;
+ };
+};
+
+///@internal static initializer for a Statement.
+#define QPID_LOG_STATEMENT_INIT(level) \
+ { 0, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION, (::qpid::log::level) }
+
+/**
+ * Like QPID_LOG but computes an additional boolean test expression
+ * to determine if the message should be logged. Evaluation of both
+ * the test and message expressions occurs only if the requested log level
+ * is enabled.
+ *@param LEVEL severity Level for message, should be one of:
+ * debug, info, notice, warning, error, critical. NB no qpid::log:: prefix.
+ *@param TEST message is logged only if expression TEST evaluates to true.
+ *@param MESSAGE any object with an @eostream operator<<, or a sequence
+ * like of ostreamable objects separated by @e<<.
+ */
+#define QPID_LOG_IF(LEVEL, TEST, MESSAGE) \
+ do { \
+ using ::qpid::log::Statement; \
+ static Statement stmt_= QPID_LOG_STATEMENT_INIT(LEVEL); \
+ static Statement::Initializer init_(stmt_); \
+ if (stmt_.enabled && (TEST)) \
+ stmt_.log(::qpid::Msg() << MESSAGE); \
+ } while(0)
+
+/**
+ * Macro for log statements. Example of use:
+ * @code
+ * QPID_LOG(debug, "There are " << foocount << " foos in the bar.");
+ * QPID_LOG(error, boost::format("Dohickey %s exploded") % dohicky.name());
+ * @endcode
+ *
+ * You can subscribe to log messages by level, by component, by filename
+ * or a combination @see Configuration.
+
+ *@param LEVEL severity Level for message, should be one of:
+ * debug, info, notice, warning, error, critical. NB no qpid::log:: prefix.
+ *@param MESSAGE any object with an @eostream operator<<, or a sequence
+ * like of ostreamable objects separated by @e<<.
+ */
+#define QPID_LOG(LEVEL, MESSAGE) QPID_LOG_IF(LEVEL, true, MESSAGE);
+
+}} // namespace qpid::log
+
+
+
+
+#endif /*!STATEMENT_H*/
+
diff --git a/RC9/qpid/cpp/src/qpid/log/posix/SinkOptions.cpp b/RC9/qpid/cpp/src/qpid/log/posix/SinkOptions.cpp
new file mode 100644
index 0000000000..9d51358e2e
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/log/posix/SinkOptions.cpp
@@ -0,0 +1,211 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "SinkOptions.h"
+#include "qpid/log/SinkOptions.h"
+#include "qpid/log/Logger.h"
+#include "qpid/log/OstreamOutput.h"
+#include "qpid/memory.h"
+#include "qpid/Exception.h"
+#include <iostream>
+#include <map>
+#include <string>
+#include <syslog.h>
+
+using std::string;
+using qpid::Exception;
+
+namespace {
+
+// SyslogFacilities maps from syslog values to the text equivalents.
+class SyslogFacilities {
+public:
+ typedef std::map<string, int> ByName;
+ typedef std::map<int, string> ByValue;
+
+ SyslogFacilities() {
+ struct NameValue { const char* name; int value; };
+ NameValue nameValue[] = {
+ { "AUTH", LOG_AUTH },
+ { "AUTHPRIV", LOG_AUTHPRIV },
+ { "CRON", LOG_CRON },
+ { "DAEMON", LOG_DAEMON },
+ { "FTP", LOG_FTP },
+ { "KERN", LOG_KERN },
+ { "LOCAL0", LOG_LOCAL0 },
+ { "LOCAL1", LOG_LOCAL1 },
+ { "LOCAL2", LOG_LOCAL2 },
+ { "LOCAL3", LOG_LOCAL3 },
+ { "LOCAL4", LOG_LOCAL4 },
+ { "LOCAL5", LOG_LOCAL5 },
+ { "LOCAL6", LOG_LOCAL6 },
+ { "LOCAL7", LOG_LOCAL7 },
+ { "LPR", LOG_LPR },
+ { "MAIL", LOG_MAIL },
+ { "NEWS", LOG_NEWS },
+ { "SYSLOG", LOG_SYSLOG },
+ { "USER", LOG_USER },
+ { "UUCP", LOG_UUCP }
+ };
+ for (size_t i = 0; i < sizeof(nameValue)/sizeof(nameValue[0]); ++i) {
+ byName.insert(ByName::value_type(nameValue[i].name, nameValue[i].value));
+ // Recognise with and without LOG_ prefix e.g.: AUTH and LOG_AUTH
+ byName.insert(ByName::value_type(string("LOG_")+nameValue[i].name, nameValue[i].value));
+ byValue.insert(ByValue::value_type(nameValue[i].value, string("LOG_")+nameValue[i].name));
+ }
+ }
+
+ int value(const string& name) const {
+ string key(name);
+ transform(key.begin(), key.end(), key.begin(), ::toupper);
+ ByName::const_iterator i = byName.find(key);
+ if (i == byName.end())
+ throw Exception("Not a valid syslog facility: " + name);
+ return i->second;
+ }
+
+ string name(int value) const {
+ ByValue::const_iterator i = byValue.find(value);
+ if (i == byValue.end())
+ throw Exception("Not a valid syslog value: " + value);
+ return i->second;
+ }
+
+ private:
+ ByName byName;
+ ByValue byValue;
+};
+
+// 'priorities' maps qpid log levels to syslog priorities. They are in
+// order of qpid log levels and must map to:
+// "trace", "debug", "info", "notice", "warning", "error", "critical"
+static int priorities[qpid::log::LevelTraits::COUNT] = {
+ LOG_DEBUG, LOG_DEBUG, LOG_INFO, LOG_NOTICE,
+ LOG_WARNING, LOG_ERR, LOG_CRIT
+};
+
+std::string basename(const std::string path) {
+ size_t i = path.find_last_of('/');
+ return path.substr((i == std::string::npos) ? 0 : i+1);
+}
+
+} // namespace
+
+namespace qpid {
+namespace log {
+namespace posix {
+
+std::ostream& operator<<(std::ostream& o, const SyslogFacility& f) {
+ return o << SyslogFacilities().name(f.value);
+}
+
+std::istream& operator>>(std::istream& i, SyslogFacility& f) {
+ std::string name;
+ i >> name;
+ f.value = SyslogFacilities().value(name);
+ return i;
+}
+
+class SyslogOutput : public qpid::log::Logger::Output {
+public:
+ SyslogOutput(const std::string& logName, const SyslogFacility& logFacility)
+ : name(logName), facility(logFacility.value)
+ {
+ ::openlog(name.c_str(), LOG_PID, facility);
+ }
+
+ virtual ~SyslogOutput() {
+ ::closelog();
+ }
+
+ virtual void log(const Statement& s, const std::string& m)
+ {
+ syslog(priorities[s.level], "%s", m.c_str());
+ }
+
+private:
+ std::string name;
+ int facility;
+};
+
+SinkOptions::SinkOptions(const std::string& argv0)
+ : qpid::log::SinkOptions(),
+ logToStderr(true),
+ logToStdout(false),
+ logToSyslog(false),
+ syslogName(basename(argv0)),
+ syslogFacility(LOG_DAEMON) {
+
+ addOptions()
+ ("log-to-stderr", optValue(logToStderr, "yes|no"), "Send logging output to stderr")
+ ("log-to-stdout", optValue(logToStdout, "yes|no"), "Send logging output to stdout")
+ ("log-to-file", optValue(logFile, "FILE"), "Send log output to FILE.")
+ ("log-to-syslog", optValue(logToSyslog, "yes|no"), "Send logging output to syslog;\n\tcustomize using --syslog-name and --syslog-facility")
+ ("syslog-name", optValue(syslogName, "NAME"), "Name to use in syslog messages")
+ ("syslog-facility", optValue(syslogFacility,"LOG_XXX"), "Facility to use in syslog messages")
+ ;
+
+}
+
+qpid::log::SinkOptions& SinkOptions::operator=(const qpid::log::SinkOptions& rhs) {
+ const SinkOptions *prhs = dynamic_cast<const SinkOptions*>(&rhs);
+ if (this != prhs) {
+ logToStderr = prhs->logToStderr;
+ logToStdout = prhs->logToStdout;
+ logToSyslog = prhs->logToSyslog;
+ logFile = prhs->logFile;
+ syslogName = prhs->syslogName;
+ syslogFacility.value = prhs->syslogFacility.value;
+ }
+ return *this;
+}
+
+void SinkOptions::detached(void) {
+ if (logToStderr && !logToStdout && !logToSyslog) {
+ logToStderr = false;
+ logToSyslog = true;
+ }
+}
+
+// The Logger acting on these options calls setup() to request any
+// Sinks be set up and fed back to the logger.
+void SinkOptions::setup(qpid::log::Logger *logger) {
+ if (logToStderr)
+ logger->output(make_auto_ptr<qpid::log::Logger::Output>
+ (new qpid::log::OstreamOutput(std::clog)));
+ if (logToStdout)
+ logger->output(make_auto_ptr<qpid::log::Logger::Output>
+ (new qpid::log::OstreamOutput(std::cout)));
+
+ if (logFile.length() > 0)
+ logger->output(make_auto_ptr<qpid::log::Logger::Output>
+ (new qpid::log::OstreamOutput(logFile)));
+
+ if (logToSyslog)
+ logger->output(make_auto_ptr<qpid::log::Logger::Output>
+ (new SyslogOutput(syslogName, syslogFacility)));
+
+}
+
+} // namespace qpid::log::posix
+
+SinkOptions* SinkOptions::create(const std::string& argv0) {
+ return new qpid::log::posix::SinkOptions (argv0);
+}
+
+}} // namespace qpid::log
diff --git a/RC9/qpid/cpp/src/qpid/log/posix/SinkOptions.h b/RC9/qpid/cpp/src/qpid/log/posix/SinkOptions.h
new file mode 100644
index 0000000000..d929c29025
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/log/posix/SinkOptions.h
@@ -0,0 +1,64 @@
+#ifndef QPID_LOG_POSIX_SINKOPTIONS_H
+#define QPID_LOG_POSIX_SINKOPTIONS_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/log/SinkOptions.h"
+#include <string>
+
+namespace qpid {
+namespace log {
+namespace posix {
+
+/**
+ * Provides a type that can be passed to << and >> operators to convert
+ * syslog facility values to/from strings.
+ */
+struct SyslogFacility {
+ int value;
+ SyslogFacility(int i=0) : value(i) {}
+};
+
+struct SinkOptions : public qpid::log::SinkOptions {
+ SinkOptions(const std::string& argv0);
+ virtual ~SinkOptions() {}
+
+ virtual qpid::log::SinkOptions& operator=(const qpid::log::SinkOptions& rhs);
+
+ // This allows the caller to indicate that there's no normal outputs
+ // available. For example, when running as a daemon. In these cases, the
+ // platform's "syslog"-type output should replace the default stderr
+ // unless some other sink has been selected.
+ virtual void detached(void);
+
+ // The Logger acting on these options calls setup() to request any
+ // Sinks be set up and fed back to the logger.
+ virtual void setup(qpid::log::Logger *logger);
+
+ bool logToStderr;
+ bool logToStdout;
+ bool logToSyslog;
+ std::string logFile;
+ std::string syslogName;
+ SyslogFacility syslogFacility;
+};
+
+}}} // namespace qpid::log::posix
+
+#endif /*!QPID_LOG_POSIX_SINKOPTIONS_H*/
diff --git a/RC9/qpid/cpp/src/qpid/log/windows/SinkOptions.cpp b/RC9/qpid/cpp/src/qpid/log/windows/SinkOptions.cpp
new file mode 100644
index 0000000000..cfcb965464
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/log/windows/SinkOptions.cpp
@@ -0,0 +1,148 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "SinkOptions.h"
+#include "qpid/log/SinkOptions.h"
+#include "qpid/log/Logger.h"
+#include "qpid/log/OstreamOutput.h"
+#include "qpid/memory.h"
+#include "qpid/Exception.h"
+#include <iostream>
+#include <map>
+#include <string>
+
+#include <windows.h>
+
+using qpid::Exception;
+
+namespace qpid {
+namespace log {
+namespace windows {
+
+namespace {
+
+// 'eventTypes' maps qpid log levels to Windows event types. They are in
+// order of qpid log levels and must map to:
+// "trace", "debug", "info", "notice", "warning", "error", "critical"
+static int eventTypes[qpid::log::LevelTraits::COUNT] = {
+ EVENTLOG_INFORMATION_TYPE, /* trace */
+ EVENTLOG_INFORMATION_TYPE, /* debug */
+ EVENTLOG_INFORMATION_TYPE, /* info */
+ EVENTLOG_INFORMATION_TYPE, /* notice */
+ EVENTLOG_WARNING_TYPE, /* warning */
+ EVENTLOG_ERROR_TYPE, /* error */
+ EVENTLOG_ERROR_TYPE /* critical */
+};
+
+} // namespace
+
+class EventLogOutput : public qpid::log::Logger::Output {
+public:
+ EventLogOutput(const std::string& sourceName) : logHandle(0)
+ {
+ logHandle = OpenEventLog(0, "Application");
+ }
+
+ virtual ~EventLogOutput() {
+ if (logHandle)
+ CloseEventLog(logHandle);
+ }
+
+ virtual void log(const Statement& s, const std::string& m)
+ {
+ if (logHandle) {
+ const char *msg = m.c_str();
+ ReportEvent(logHandle,
+ eventTypes[s.level],
+ 0, /* category unused */
+ 0, /* event id */
+ 0, /* user security id */
+ 1, /* number of strings */
+ 0, /* no event-specific data */
+ &msg,
+ 0);
+ }
+ }
+
+private:
+ HANDLE logHandle;
+};
+
+SinkOptions::SinkOptions(const std::string& argv0)
+ : qpid::log::SinkOptions(),
+ logToStderr(true),
+ logToStdout(false),
+ logToEventLog(false),
+ eventSource("Application")
+{
+ addOptions()
+ ("log-to-stderr", optValue(logToStderr, "yes|no"), "Send logging output to stderr")
+ ("log-to-stdout", optValue(logToStdout, "yes|no"), "Send logging output to stdout")
+ ("log-to-file", optValue(logFile, "FILE"), "Send log output to FILE.")
+ ("log-to-eventlog", optValue(logToEventLog, "yes|no"), "Send logging output to event log;\n\tcustomize using --syslog-name and --syslog-facility")
+ ("eventlog-source-name", optValue(eventSource, "Application"), "Event source to log to")
+ ;
+
+}
+
+qpid::log::SinkOptions& SinkOptions::operator=(const qpid::log::SinkOptions& rhs) {
+ const SinkOptions *prhs = dynamic_cast<const SinkOptions*>(&rhs);
+ if (this != prhs) {
+ logToStderr = prhs->logToStderr;
+ logToStdout = prhs->logToStdout;
+ logToEventLog = prhs->logToEventLog;
+ eventSource = prhs->eventSource;
+ logFile = prhs->logFile;
+ }
+ return *this;
+}
+
+void SinkOptions::detached(void) {
+ if (logToStderr && !logToStdout && !logToEventLog) {
+ logToStderr = false;
+ logToEventLog = true;
+ }
+}
+
+// The Logger acting on these options calls setup() to request any
+// Sinks be set up and fed back to the logger.
+void SinkOptions::setup(qpid::log::Logger *logger) {
+ if (logToStderr)
+ logger->output(make_auto_ptr<qpid::log::Logger::Output>
+ (new qpid::log::OstreamOutput(std::clog)));
+ if (logToStdout)
+ logger->output(make_auto_ptr<qpid::log::Logger::Output>
+ (new qpid::log::OstreamOutput(std::cout)));
+
+ if (logFile.length() > 0)
+ logger->output(make_auto_ptr<qpid::log::Logger::Output>
+ (new qpid::log::OstreamOutput(logFile)));
+
+ if (logToEventLog)
+ logger->output(make_auto_ptr<qpid::log::Logger::Output>
+ (new EventLogOutput(eventSource)));
+
+}
+
+} // namespace windows
+
+SinkOptions* SinkOptions::create(const std::string& argv0) {
+ return new qpid::log::windows::SinkOptions (argv0);
+}
+
+}} // namespace qpid::log
diff --git a/RC9/qpid/cpp/src/qpid/log/windows/SinkOptions.h b/RC9/qpid/cpp/src/qpid/log/windows/SinkOptions.h
new file mode 100644
index 0000000000..d14e9352be
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/log/windows/SinkOptions.h
@@ -0,0 +1,54 @@
+#ifndef QPID_LOG_WINDOWS_SINKOPTIONS_H
+#define QPID_LOG_WINDOWS_SINKOPTIONS_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/log/SinkOptions.h"
+#include <string>
+
+namespace qpid {
+namespace log {
+namespace windows {
+
+struct SinkOptions : public qpid::log::SinkOptions {
+ SinkOptions(const std::string& argv0);
+ virtual ~SinkOptions() {}
+
+ virtual qpid::log::SinkOptions& operator=(const qpid::log::SinkOptions& rhs);
+
+ // This allows the caller to indicate that there's no normal outputs
+ // available. For example, when running as a service. In these cases, the
+ // platform's "syslog"-type output should replace the default stderr
+ // unless some other sink has been selected.
+ virtual void detached(void);
+
+ // The Logger acting on these options calls setup() to request any
+ // Sinks be set up and fed back to the logger.
+ virtual void setup(qpid::log::Logger *logger);
+
+ bool logToStderr;
+ bool logToStdout;
+ bool logToEventLog;
+ std::string eventSource;
+ std::string logFile;
+};
+
+}}} // namespace qpid::log::windows
+
+#endif /*!QPID_LOG_WINDOWS_SINKOPTIONS_H*/
diff --git a/RC9/qpid/cpp/src/qpid/management/Args.h b/RC9/qpid/cpp/src/qpid/management/Args.h
new file mode 100644
index 0000000000..da1fb033b9
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/management/Args.h
@@ -0,0 +1,44 @@
+#ifndef _Args_
+#define _Args_
+
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+
+namespace qpid {
+namespace management {
+
+class Args
+{
+ public:
+
+ virtual ~Args (void) = 0;
+
+};
+
+inline Args::~Args (void) {}
+
+class ArgsNone : public Args
+{
+};
+
+}}
+
+
+#endif /*!_Args_*/
diff --git a/RC9/qpid/cpp/src/qpid/management/Manageable.cpp b/RC9/qpid/cpp/src/qpid/management/Manageable.cpp
new file mode 100644
index 0000000000..08bb541fc7
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/management/Manageable.cpp
@@ -0,0 +1,48 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+#include "Manageable.h"
+
+using namespace qpid::management;
+using std::string;
+
+string Manageable::StatusText (status_t status, string text)
+{
+ if ((status & STATUS_USER) == STATUS_USER)
+ return text;
+
+ switch (status)
+ {
+ case STATUS_OK : return "OK";
+ case STATUS_UNKNOWN_OBJECT : return "UnknownObject";
+ case STATUS_UNKNOWN_METHOD : return "UnknownMethod";
+ case STATUS_NOT_IMPLEMENTED : return "NotImplemented";
+ case STATUS_INVALID_PARAMETER : return "InvalidParameter";
+ case STATUS_FEATURE_NOT_IMPLEMENTED : return "FeatureNotImplemented";
+ case STATUS_FORBIDDEN : return "Forbidden";
+ }
+
+ return "??";
+}
+
+Manageable::status_t Manageable::ManagementMethod (uint32_t, Args&, std::string&)
+{
+ return STATUS_UNKNOWN_METHOD;
+}
+
diff --git a/RC9/qpid/cpp/src/qpid/management/Manageable.h b/RC9/qpid/cpp/src/qpid/management/Manageable.h
new file mode 100644
index 0000000000..b4d80d8fad
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/management/Manageable.h
@@ -0,0 +1,71 @@
+#ifndef _Manageable_
+#define _Manageable_
+
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+#include "ManagementObject.h"
+#include "Args.h"
+#include <string>
+
+namespace qpid {
+namespace management {
+
+class Manageable
+{
+ public:
+
+ virtual ~Manageable(void) = 0;
+
+ // status_t is a type used to pass completion status from the method handler.
+ //
+ typedef uint32_t status_t;
+ static std::string StatusText(status_t status, std::string text = std::string());
+
+ static const status_t STATUS_OK = 0;
+ static const status_t STATUS_UNKNOWN_OBJECT = 1;
+ static const status_t STATUS_UNKNOWN_METHOD = 2;
+ static const status_t STATUS_NOT_IMPLEMENTED = 3;
+ static const status_t STATUS_INVALID_PARAMETER = 4;
+ static const status_t STATUS_FEATURE_NOT_IMPLEMENTED = 5;
+ static const status_t STATUS_FORBIDDEN = 6;
+ static const status_t STATUS_EXCEPTION = 7;
+ static const status_t STATUS_USER = 0x00010000;
+
+ // Every "Manageable" object must hold a reference to exactly one
+ // management object. This object is always of a class derived from
+ // the pure-virtual "ManagementObject".
+ //
+ // This accessor function returns a pointer to the management object.
+ //
+ virtual ManagementObject* GetManagementObject(void) const = 0;
+
+ // Every "Manageable" object must implement ManagementMethod. This
+ // function is called when a remote management client invokes a method
+ // on this object. The input and output arguments are specific to the
+ // method being called and must be down-cast to the appropriate sub class
+ // before use.
+ virtual status_t ManagementMethod(uint32_t methodId, Args& args, std::string& text);
+};
+
+inline Manageable::~Manageable(void) {}
+
+}}
+
+#endif /*!_Manageable_*/
diff --git a/RC9/qpid/cpp/src/qpid/management/ManagementBroker.cpp b/RC9/qpid/cpp/src/qpid/management/ManagementBroker.cpp
new file mode 100644
index 0000000000..cc7a2dc4f3
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/management/ManagementBroker.cpp
@@ -0,0 +1,1138 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "ManagementBroker.h"
+#include "qpid/broker/DeliverableMessage.h"
+#include "qpid/log/Statement.h"
+#include <qpid/broker/Message.h>
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/sys/Time.h"
+#include "qpid/broker/ConnectionState.h"
+#include "qpid/broker/AclModule.h"
+#include <list>
+#include <iostream>
+#include <fstream>
+
+using boost::intrusive_ptr;
+using qpid::framing::Uuid;
+using namespace qpid::framing;
+using namespace qpid::management;
+using namespace qpid::broker;
+using namespace qpid::sys;
+using namespace std;
+namespace _qmf = qmf::org::apache::qpid::broker;
+
+Mutex ManagementAgent::Singleton::lock;
+bool ManagementAgent::Singleton::disabled = false;
+ManagementAgent* ManagementAgent::Singleton::agent = 0;
+int ManagementAgent::Singleton::refCount = 0;
+
+ManagementAgent::Singleton::Singleton(bool disableManagement)
+{
+ Mutex::ScopedLock _lock(lock);
+ if (disableManagement && !disabled) {
+ disabled = true;
+ assert(refCount == 0); // can't disable after agent has been allocated
+ }
+ if (refCount == 0 && !disabled)
+ agent = new ManagementBroker();
+ refCount++;
+}
+
+ManagementAgent::Singleton::~Singleton()
+{
+ Mutex::ScopedLock _lock(lock);
+ refCount--;
+ if (refCount == 0 && !disabled) {
+ delete agent;
+ agent = 0;
+ }
+}
+
+ManagementAgent* ManagementAgent::Singleton::getInstance()
+{
+ return agent;
+}
+
+ManagementBroker::RemoteAgent::~RemoteAgent ()
+{
+ if (mgmtObject != 0)
+ mgmtObject->resourceDestroy();
+}
+
+ManagementBroker::ManagementBroker () :
+ threadPoolSize(1), interval(10), broker(0)
+{
+ nextObjectId = 1;
+ brokerBank = 1;
+ bootSequence = 1;
+ nextRemoteBank = 10;
+ nextRequestSequence = 1;
+ clientWasAdded = false;
+}
+
+ManagementBroker::~ManagementBroker ()
+{
+ timer.stop();
+ {
+ Mutex::ScopedLock lock (userLock);
+
+ // Reset the shared pointers to exchanges. If this is not done now, the exchanges
+ // will stick around until dExchange and mExchange are implicitely destroyed (long
+ // after this destructor completes). Those exchanges hold references to management
+ // objects that will be invalid.
+ dExchange.reset();
+ mExchange.reset();
+
+ moveNewObjectsLH();
+ for (ManagementObjectMap::iterator iter = managementObjects.begin ();
+ iter != managementObjects.end ();
+ iter++) {
+ ManagementObject* object = iter->second;
+ delete object;
+ }
+ managementObjects.clear();
+ }
+}
+
+void ManagementBroker::configure(const string& _dataDir, uint16_t _interval,
+ qpid::broker::Broker* _broker, int _threads)
+{
+ dataDir = _dataDir;
+ interval = _interval;
+ broker = _broker;
+ threadPoolSize = _threads;
+ timer.add (intrusive_ptr<TimerTask> (new Periodic(*this, interval)));
+
+ // Get from file or generate and save to file.
+ if (dataDir.empty())
+ {
+ uuid.generate();
+ QPID_LOG (info, "ManagementBroker has no data directory, generated new broker ID: "
+ << uuid);
+ }
+ else
+ {
+ string filename(dataDir + "/.mbrokerdata");
+ ifstream inFile(filename.c_str ());
+
+ if (inFile.good())
+ {
+ inFile >> uuid;
+ inFile >> bootSequence;
+ inFile >> nextRemoteBank;
+ inFile.close();
+ QPID_LOG (debug, "ManagementBroker restored broker ID: " << uuid);
+
+ // if sequence goes beyond a 12-bit field, skip zero and wrap to 1.
+ bootSequence++;
+ if (bootSequence & 0xF000)
+ bootSequence = 1;
+ writeData();
+ }
+ else
+ {
+ uuid.generate();
+ QPID_LOG (info, "ManagementBroker generated broker ID: " << uuid);
+ writeData();
+ }
+
+ QPID_LOG (debug, "ManagementBroker boot sequence: " << bootSequence);
+ }
+}
+
+void ManagementBroker::writeData ()
+{
+ string filename (dataDir + "/.mbrokerdata");
+ ofstream outFile (filename.c_str ());
+
+ if (outFile.good())
+ {
+ outFile << uuid << " " << bootSequence << " " << nextRemoteBank << endl;
+ outFile.close();
+ }
+}
+
+void ManagementBroker::setExchange (qpid::broker::Exchange::shared_ptr _mexchange,
+ qpid::broker::Exchange::shared_ptr _dexchange)
+{
+ mExchange = _mexchange;
+ dExchange = _dexchange;
+}
+
+void ManagementBroker::registerClass (const string& packageName,
+ const string& className,
+ uint8_t* md5Sum,
+ ManagementObject::writeSchemaCall_t schemaCall)
+{
+ Mutex::ScopedLock lock(userLock);
+ PackageMap::iterator pIter = findOrAddPackageLH(packageName);
+ addClassLH(ManagementItem::CLASS_KIND_TABLE, pIter, className, md5Sum, schemaCall);
+}
+
+void ManagementBroker::registerEvent (const string& packageName,
+ const string& eventName,
+ uint8_t* md5Sum,
+ ManagementObject::writeSchemaCall_t schemaCall)
+{
+ Mutex::ScopedLock lock(userLock);
+ PackageMap::iterator pIter = findOrAddPackageLH(packageName);
+ addClassLH(ManagementItem::CLASS_KIND_EVENT, pIter, eventName, md5Sum, schemaCall);
+}
+
+ObjectId ManagementBroker::addObject (ManagementObject* object,
+ uint64_t persistId)
+{
+ Mutex::ScopedLock lock (addLock);
+ uint16_t sequence;
+ uint64_t objectNum;
+
+ if (persistId == 0) {
+ sequence = bootSequence;
+ objectNum = nextObjectId++;
+ } else {
+ sequence = 0;
+ objectNum = persistId;
+ }
+
+ ObjectId objId(0 /*flags*/ , sequence, brokerBank, 0, objectNum);
+
+ object->setObjectId(objId);
+ newManagementObjects[objId] = object;
+ return objId;
+}
+
+void ManagementBroker::raiseEvent(const ManagementEvent& event, severity_t severity)
+{
+ Mutex::ScopedLock lock (userLock);
+ Buffer outBuffer(eventBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+ uint8_t sev = (severity == SEV_DEFAULT) ? event.getSeverity() : (uint8_t) severity;
+
+ encodeHeader(outBuffer, 'e');
+ outBuffer.putShortString(event.getPackageName());
+ outBuffer.putShortString(event.getEventName());
+ outBuffer.putBin128(event.getMd5Sum());
+ outBuffer.putLongLong(uint64_t(Duration(now())));
+ outBuffer.putOctet(sev);
+ event.encode(outBuffer);
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
+ outBuffer.reset();
+ sendBuffer(outBuffer, outLen, mExchange,
+ "console.event.1.0." + event.getPackageName() + "." + event.getEventName());
+}
+
+ManagementBroker::Periodic::Periodic (ManagementBroker& _broker, uint32_t _seconds)
+ : TimerTask (qpid::sys::Duration ((_seconds ? _seconds : 1) * qpid::sys::TIME_SEC)), broker(_broker) {}
+
+ManagementBroker::Periodic::~Periodic () {}
+
+void ManagementBroker::Periodic::fire ()
+{
+ broker.timer.add (intrusive_ptr<TimerTask> (new Periodic (broker, broker.interval)));
+ broker.periodicProcessing ();
+}
+
+void ManagementBroker::clientAdded (const std::string& routingKey)
+{
+ if (routingKey.find("console") != 0)
+ return;
+
+ clientWasAdded = true;
+ for (RemoteAgentMap::iterator aIter = remoteAgents.begin();
+ aIter != remoteAgents.end();
+ aIter++) {
+ char localBuffer[16];
+ Buffer outBuffer(localBuffer, 16);
+ uint32_t outLen;
+
+ encodeHeader(outBuffer, 'x');
+ outLen = outBuffer.getPosition();
+ outBuffer.reset();
+ sendBuffer(outBuffer, outLen, dExchange, aIter->second->routingKey);
+ }
+}
+
+void ManagementBroker::encodeHeader (Buffer& buf, uint8_t opcode, uint32_t seq)
+{
+ buf.putOctet ('A');
+ buf.putOctet ('M');
+ buf.putOctet ('2');
+ buf.putOctet (opcode);
+ buf.putLong (seq);
+}
+
+bool ManagementBroker::checkHeader (Buffer& buf, uint8_t *opcode, uint32_t *seq)
+{
+ uint8_t h1 = buf.getOctet();
+ uint8_t h2 = buf.getOctet();
+ uint8_t h3 = buf.getOctet();
+
+ *opcode = buf.getOctet();
+ *seq = buf.getLong();
+
+ return h1 == 'A' && h2 == 'M' && h3 == '2';
+}
+
+void ManagementBroker::sendBuffer(Buffer& buf,
+ uint32_t length,
+ qpid::broker::Exchange::shared_ptr exchange,
+ string routingKey)
+{
+ if (exchange.get() == 0)
+ return;
+
+ intrusive_ptr<Message> msg(new Message());
+ AMQFrame method(in_place<MessageTransferBody>(
+ ProtocolVersion(), exchange->getName (), 0, 0));
+ AMQFrame header(in_place<AMQHeaderBody>());
+ AMQFrame content(in_place<AMQContentBody>());
+
+ content.castBody<AMQContentBody>()->decode(buf, length);
+
+ method.setEof(false);
+ header.setBof(false);
+ header.setEof(false);
+ content.setBof(false);
+
+ msg->getFrames().append(method);
+ msg->getFrames().append(header);
+
+ MessageProperties* props =
+ msg->getFrames().getHeaders()->get<MessageProperties>(true);
+ props->setContentLength(length);
+ msg->getFrames().append(content);
+
+ DeliverableMessage deliverable (msg);
+ try {
+ exchange->route(deliverable, routingKey, 0);
+ } catch(exception&) {}
+}
+
+void ManagementBroker::moveNewObjectsLH()
+{
+ Mutex::ScopedLock lock (addLock);
+ for (ManagementObjectMap::iterator iter = newManagementObjects.begin ();
+ iter != newManagementObjects.end ();
+ iter++)
+ managementObjects[iter->first] = iter->second;
+ newManagementObjects.clear();
+}
+
+void ManagementBroker::periodicProcessing (void)
+{
+#define BUFSIZE 65536
+ Mutex::ScopedLock lock (userLock);
+ char msgChars[BUFSIZE];
+ uint32_t contentSize;
+ string routingKey;
+ list<pair<ObjectId, ManagementObject*> > deleteList;
+
+ moveNewObjectsLH();
+
+ if (clientWasAdded) {
+ clientWasAdded = false;
+ for (ManagementObjectMap::iterator iter = managementObjects.begin ();
+ iter != managementObjects.end ();
+ iter++) {
+ ManagementObject* object = iter->second;
+ object->setForcePublish(true);
+ }
+ }
+
+ for (ManagementObjectMap::iterator iter = managementObjects.begin ();
+ iter != managementObjects.end ();
+ iter++) {
+ ManagementObject* object = iter->second;
+
+ if (object->getConfigChanged() || object->getInstChanged())
+ object->setUpdateTime();
+
+ if (object->getConfigChanged() || object->getForcePublish() || object->isDeleted()) {
+ Buffer msgBuffer (msgChars, BUFSIZE);
+ encodeHeader (msgBuffer, 'c');
+ object->writeProperties(msgBuffer);
+
+ contentSize = BUFSIZE - msgBuffer.available ();
+ msgBuffer.reset ();
+ routingKey = "console.obj.1.0." + object->getPackageName() + "." + object->getClassName();
+ sendBuffer (msgBuffer, contentSize, mExchange, routingKey);
+ }
+
+ if (object->hasInst() && (object->getInstChanged() || object->getForcePublish())) {
+ Buffer msgBuffer (msgChars, BUFSIZE);
+ encodeHeader (msgBuffer, 'i');
+ object->writeStatistics(msgBuffer);
+
+ contentSize = BUFSIZE - msgBuffer.available ();
+ msgBuffer.reset ();
+ routingKey = "console.obj.1.0." + object->getPackageName() + "." + object->getClassName();
+ sendBuffer (msgBuffer, contentSize, mExchange, routingKey);
+ }
+
+ if (object->isDeleted())
+ deleteList.push_back(pair<ObjectId, ManagementObject*>(iter->first, object));
+ object->setForcePublish(false);
+ }
+
+ // Delete flagged objects
+ for (list<pair<ObjectId, ManagementObject*> >::reverse_iterator iter = deleteList.rbegin();
+ iter != deleteList.rend();
+ iter++) {
+ delete iter->second;
+ managementObjects.erase(iter->first);
+ }
+
+ if (!deleteList.empty()) {
+ deleteList.clear();
+ deleteOrphanedAgentsLH();
+ }
+
+ {
+ Buffer msgBuffer(msgChars, BUFSIZE);
+ encodeHeader(msgBuffer, 'h');
+ msgBuffer.putLongLong(uint64_t(Duration(now())));
+
+ contentSize = BUFSIZE - msgBuffer.available ();
+ msgBuffer.reset ();
+ routingKey = "console.heartbeat.1.0";
+ sendBuffer (msgBuffer, contentSize, mExchange, routingKey);
+ }
+}
+
+void ManagementBroker::sendCommandComplete (string replyToKey, uint32_t sequence,
+ uint32_t code, string text)
+{
+ Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ encodeHeader (outBuffer, 'z', sequence);
+ outBuffer.putLong (code);
+ outBuffer.putShortString (text);
+ outLen = MA_BUFFER_SIZE - outBuffer.available ();
+ outBuffer.reset ();
+ sendBuffer (outBuffer, outLen, dExchange, replyToKey);
+}
+
+bool ManagementBroker::dispatchCommand (Deliverable& deliverable,
+ const string& routingKey,
+ const FieldTable* /*args*/)
+{
+ Mutex::ScopedLock lock (userLock);
+ Message& msg = ((DeliverableMessage&) deliverable).getMessage ();
+
+ // Parse the routing key. This management broker should act as though it
+ // is bound to the exchange to match the following keys:
+ //
+ // agent.1.0.#
+ // broker
+ // schema.#
+
+ if (routingKey == "broker") {
+ dispatchAgentCommandLH(msg);
+ return false;
+ }
+
+ else if (routingKey.compare(0, 9, "agent.1.0") == 0) {
+ dispatchAgentCommandLH(msg);
+ return false;
+ }
+
+ else if (routingKey.compare(0, 8, "agent.1.") == 0) {
+ return authorizeAgentMessageLH(msg);
+ }
+
+ else if (routingKey.compare(0, 7, "schema.") == 0) {
+ dispatchAgentCommandLH(msg);
+ return true;
+ }
+
+ return true;
+}
+
+void ManagementBroker::handleMethodRequestLH (Buffer& inBuffer, string replyToKey,
+ uint32_t sequence, const ConnectionToken* connToken)
+{
+ string methodName;
+ string packageName;
+ string className;
+ uint8_t hash[16];
+ Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+ AclModule* acl = broker->getAcl();
+
+ ObjectId objId(inBuffer);
+ inBuffer.getShortString(packageName);
+ inBuffer.getShortString(className);
+ inBuffer.getBin128(hash);
+ inBuffer.getShortString(methodName);
+ encodeHeader(outBuffer, 'm', sequence);
+
+ if (acl != 0) {
+ string userId = ((const qpid::broker::ConnectionState*) connToken)->getUserId();
+ map<acl::Property, string> params;
+ params[acl::PROP_SCHEMAPACKAGE] = packageName;
+ params[acl::PROP_SCHEMACLASS] = className;
+
+ if (!acl->authorise(userId, acl::ACT_ACCESS, acl::OBJ_METHOD, methodName, &params)) {
+ outBuffer.putLong(Manageable::STATUS_FORBIDDEN);
+ outBuffer.putMediumString(Manageable::StatusText(Manageable::STATUS_FORBIDDEN));
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
+ outBuffer.reset();
+ sendBuffer(outBuffer, outLen, dExchange, replyToKey);
+ return;
+ }
+ }
+
+ ManagementObjectMap::iterator iter = managementObjects.find(objId);
+ if (iter == managementObjects.end() || iter->second->isDeleted()) {
+ outBuffer.putLong (Manageable::STATUS_UNKNOWN_OBJECT);
+ outBuffer.putMediumString(Manageable::StatusText (Manageable::STATUS_UNKNOWN_OBJECT));
+ } else {
+ if ((iter->second->getPackageName() != packageName) ||
+ (iter->second->getClassName() != className)) {
+ outBuffer.putLong (Manageable::STATUS_INVALID_PARAMETER);
+ outBuffer.putMediumString(Manageable::StatusText (Manageable::STATUS_INVALID_PARAMETER));
+ }
+ else
+ try {
+ outBuffer.record();
+ iter->second->doMethod(methodName, inBuffer, outBuffer);
+ } catch(exception& e) {
+ outBuffer.restore();
+ outBuffer.putLong(Manageable::STATUS_EXCEPTION);
+ outBuffer.putMediumString(e.what());
+ }
+ }
+
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
+ outBuffer.reset();
+ sendBuffer(outBuffer, outLen, dExchange, replyToKey);
+}
+
+void ManagementBroker::handleBrokerRequestLH (Buffer&, string replyToKey, uint32_t sequence)
+{
+ Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ encodeHeader (outBuffer, 'b', sequence);
+ uuid.encode (outBuffer);
+
+ outLen = MA_BUFFER_SIZE - outBuffer.available ();
+ outBuffer.reset ();
+ sendBuffer (outBuffer, outLen, dExchange, replyToKey);
+}
+
+void ManagementBroker::handlePackageQueryLH (Buffer&, string replyToKey, uint32_t sequence)
+{
+ for (PackageMap::iterator pIter = packages.begin ();
+ pIter != packages.end ();
+ pIter++)
+ {
+ Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ encodeHeader (outBuffer, 'p', sequence);
+ encodePackageIndication (outBuffer, pIter);
+ outLen = MA_BUFFER_SIZE - outBuffer.available ();
+ outBuffer.reset ();
+ sendBuffer (outBuffer, outLen, dExchange, replyToKey);
+ }
+
+ sendCommandComplete (replyToKey, sequence);
+}
+
+void ManagementBroker::handlePackageIndLH (Buffer& inBuffer, string /*replyToKey*/, uint32_t /*sequence*/)
+{
+ string packageName;
+
+ inBuffer.getShortString(packageName);
+ findOrAddPackageLH(packageName);
+}
+
+void ManagementBroker::handleClassQueryLH(Buffer& inBuffer, string replyToKey, uint32_t sequence)
+{
+ string packageName;
+
+ inBuffer.getShortString(packageName);
+ PackageMap::iterator pIter = packages.find(packageName);
+ if (pIter != packages.end())
+ {
+ ClassMap cMap = pIter->second;
+ for (ClassMap::iterator cIter = cMap.begin();
+ cIter != cMap.end();
+ cIter++)
+ {
+ if (cIter->second.hasSchema())
+ {
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ encodeHeader(outBuffer, 'q', sequence);
+ encodeClassIndication(outBuffer, pIter, cIter);
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
+ outBuffer.reset();
+ sendBuffer(outBuffer, outLen, dExchange, replyToKey);
+ }
+ }
+ }
+ sendCommandComplete(replyToKey, sequence);
+}
+
+void ManagementBroker::handleClassIndLH (Buffer& inBuffer, string replyToKey, uint32_t)
+{
+ string packageName;
+ SchemaClassKey key;
+
+ uint8_t kind = inBuffer.getOctet();
+ inBuffer.getShortString(packageName);
+ inBuffer.getShortString(key.name);
+ inBuffer.getBin128(key.hash);
+
+ PackageMap::iterator pIter = findOrAddPackageLH(packageName);
+ ClassMap::iterator cIter = pIter->second.find(key);
+ if (cIter == pIter->second.end() || !cIter->second.hasSchema()) {
+ Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+ uint32_t sequence = nextRequestSequence++;
+
+ encodeHeader (outBuffer, 'S', sequence);
+ outBuffer.putShortString(packageName);
+ outBuffer.putShortString(key.name);
+ outBuffer.putBin128(key.hash);
+ outLen = MA_BUFFER_SIZE - outBuffer.available ();
+ outBuffer.reset ();
+ sendBuffer (outBuffer, outLen, dExchange, replyToKey);
+
+ if (cIter != pIter->second.end())
+ pIter->second.erase(key);
+
+ pIter->second.insert(pair<SchemaClassKey, SchemaClass>(key, SchemaClass(kind, sequence)));
+ }
+}
+
+void ManagementBroker::SchemaClass::appendSchema(Buffer& buf)
+{
+ // If the management package is attached locally (embedded in the broker or
+ // linked in via plug-in), call the schema handler directly. If the package
+ // is from a remote management agent, send the stored schema information.
+
+ if (writeSchemaCall != 0)
+ writeSchemaCall(buf);
+ else
+ buf.putRawData(buffer, bufferLen);
+}
+
+void ManagementBroker::handleSchemaRequestLH(Buffer& inBuffer, string replyToKey, uint32_t sequence)
+{
+ string packageName;
+ SchemaClassKey key;
+
+ inBuffer.getShortString (packageName);
+ inBuffer.getShortString (key.name);
+ inBuffer.getBin128 (key.hash);
+
+ PackageMap::iterator pIter = packages.find(packageName);
+ if (pIter != packages.end()) {
+ ClassMap& cMap = pIter->second;
+ ClassMap::iterator cIter = cMap.find(key);
+ if (cIter != cMap.end()) {
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+ SchemaClass& classInfo = cIter->second;
+
+ if (classInfo.hasSchema()) {
+ encodeHeader(outBuffer, 's', sequence);
+ classInfo.appendSchema(outBuffer);
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
+ outBuffer.reset();
+ sendBuffer(outBuffer, outLen, dExchange, replyToKey);
+ }
+ else
+ sendCommandComplete(replyToKey, sequence, 1, "Schema not available");
+ }
+ else
+ sendCommandComplete(replyToKey, sequence, 1, "Class key not found");
+ }
+ else
+ sendCommandComplete(replyToKey, sequence, 1, "Package not found");
+}
+
+void ManagementBroker::handleSchemaResponseLH(Buffer& inBuffer, string /*replyToKey*/, uint32_t sequence)
+{
+ string packageName;
+ SchemaClassKey key;
+
+ inBuffer.record();
+ inBuffer.getOctet();
+ inBuffer.getShortString(packageName);
+ inBuffer.getShortString(key.name);
+ inBuffer.getBin128(key.hash);
+ inBuffer.restore();
+
+ PackageMap::iterator pIter = packages.find(packageName);
+ if (pIter != packages.end()) {
+ ClassMap& cMap = pIter->second;
+ ClassMap::iterator cIter = cMap.find(key);
+ if (cIter != cMap.end() && cIter->second.pendingSequence == sequence) {
+ size_t length = validateSchema(inBuffer, cIter->second.kind);
+ if (length == 0) {
+ QPID_LOG(warning, "Management Broker received invalid schema response: " << packageName << "." << key.name);
+ cMap.erase(key);
+ } else {
+ cIter->second.buffer = (uint8_t*) malloc(length);
+ cIter->second.bufferLen = length;
+ inBuffer.getRawData(cIter->second.buffer, cIter->second.bufferLen);
+
+ // Publish a class-indication message
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ encodeHeader(outBuffer, 'q');
+ encodeClassIndication(outBuffer, pIter, cIter);
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
+ outBuffer.reset();
+ sendBuffer(outBuffer, outLen, mExchange, "schema.class");
+ }
+ }
+ }
+}
+
+bool ManagementBroker::bankInUse (uint32_t bank)
+{
+ for (RemoteAgentMap::iterator aIter = remoteAgents.begin();
+ aIter != remoteAgents.end();
+ aIter++)
+ if (aIter->second->agentBank == bank)
+ return true;
+ return false;
+}
+
+uint32_t ManagementBroker::allocateNewBank ()
+{
+ while (bankInUse (nextRemoteBank))
+ nextRemoteBank++;
+
+ uint32_t allocated = nextRemoteBank++;
+ writeData ();
+ return allocated;
+}
+
+uint32_t ManagementBroker::assignBankLH (uint32_t requestedBank)
+{
+ if (requestedBank == 0 || bankInUse (requestedBank))
+ return allocateNewBank ();
+ return requestedBank;
+}
+
+void ManagementBroker::deleteOrphanedAgentsLH()
+{
+ vector<ObjectId> deleteList;
+
+ for (RemoteAgentMap::iterator aIter = remoteAgents.begin(); aIter != remoteAgents.end(); aIter++) {
+ ObjectId connectionRef = aIter->first;
+ bool found = false;
+
+ for (ManagementObjectMap::iterator iter = managementObjects.begin();
+ iter != managementObjects.end();
+ iter++) {
+ if (iter->first == connectionRef && !iter->second->isDeleted()) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ deleteList.push_back(connectionRef);
+ delete aIter->second;
+ }
+ }
+
+ for (vector<ObjectId>::iterator dIter = deleteList.begin(); dIter != deleteList.end(); dIter++)
+ remoteAgents.erase(*dIter);
+
+ deleteList.clear();
+}
+
+void ManagementBroker::handleAttachRequestLH (Buffer& inBuffer, string replyToKey, uint32_t sequence, const ConnectionToken* connToken)
+{
+ string label;
+ uint32_t requestedBrokerBank, requestedAgentBank;
+ uint32_t assignedBank;
+ ObjectId connectionRef = ((const ConnectionState*) connToken)->GetManagementObject()->getObjectId();
+ Uuid systemId;
+
+ moveNewObjectsLH();
+ deleteOrphanedAgentsLH();
+ RemoteAgentMap::iterator aIter = remoteAgents.find(connectionRef);
+ if (aIter != remoteAgents.end()) {
+ // There already exists an agent on this session. Reject the request.
+ sendCommandComplete(replyToKey, sequence, 1, "Connection already has remote agent");
+ return;
+ }
+
+ inBuffer.getShortString(label);
+ systemId.decode(inBuffer);
+ requestedBrokerBank = inBuffer.getLong();
+ requestedAgentBank = inBuffer.getLong();
+ assignedBank = assignBankLH(requestedAgentBank);
+
+ RemoteAgent* agent = new RemoteAgent;
+ agent->brokerBank = brokerBank;
+ agent->agentBank = assignedBank;
+ agent->routingKey = replyToKey;
+ agent->connectionRef = connectionRef;
+ agent->mgmtObject = new _qmf::Agent (this, agent);
+ agent->mgmtObject->set_connectionRef(agent->connectionRef);
+ agent->mgmtObject->set_label (label);
+ agent->mgmtObject->set_registeredTo (broker->GetManagementObject()->getObjectId());
+ agent->mgmtObject->set_systemId (systemId);
+ agent->mgmtObject->set_brokerBank (brokerBank);
+ agent->mgmtObject->set_agentBank (assignedBank);
+ addObject (agent->mgmtObject);
+
+ remoteAgents[connectionRef] = agent;
+
+ // Send an Attach Response
+ Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ encodeHeader (outBuffer, 'a', sequence);
+ outBuffer.putLong (brokerBank);
+ outBuffer.putLong (assignedBank);
+ outLen = MA_BUFFER_SIZE - outBuffer.available ();
+ outBuffer.reset ();
+ sendBuffer (outBuffer, outLen, dExchange, replyToKey);
+}
+
+void ManagementBroker::handleGetQueryLH (Buffer& inBuffer, string replyToKey, uint32_t sequence)
+{
+ FieldTable ft;
+ FieldTable::ValuePtr value;
+
+ moveNewObjectsLH();
+
+ ft.decode(inBuffer);
+ value = ft.get("_class");
+ if (value.get() == 0 || !value->convertsTo<string>()) {
+ value = ft.get("_objectid");
+ if (value.get() == 0 || !value->convertsTo<string>())
+ return;
+
+ ObjectId selector(value->get<string>());
+ ManagementObjectMap::iterator iter = managementObjects.find(selector);
+ if (iter != managementObjects.end()) {
+ ManagementObject* object = iter->second;
+ Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ encodeHeader(outBuffer, 'g', sequence);
+ object->writeProperties(outBuffer);
+ object->writeStatistics(outBuffer, true);
+ outLen = MA_BUFFER_SIZE - outBuffer.available ();
+ outBuffer.reset ();
+ sendBuffer(outBuffer, outLen, dExchange, replyToKey);
+ }
+ sendCommandComplete(replyToKey, sequence);
+ return;
+ }
+
+ string className (value->get<string>());
+
+ for (ManagementObjectMap::iterator iter = managementObjects.begin();
+ iter != managementObjects.end();
+ iter++) {
+ ManagementObject* object = iter->second;
+ if (object->getClassName () == className) {
+ Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ encodeHeader(outBuffer, 'g', sequence);
+ object->writeProperties(outBuffer);
+ object->writeStatistics(outBuffer, true);
+ outLen = MA_BUFFER_SIZE - outBuffer.available ();
+ outBuffer.reset ();
+ sendBuffer(outBuffer, outLen, dExchange, replyToKey);
+ }
+ }
+
+ sendCommandComplete(replyToKey, sequence);
+}
+
+bool ManagementBroker::authorizeAgentMessageLH(Message& msg)
+{
+ Buffer inBuffer (inputBuffer, MA_BUFFER_SIZE);
+ uint8_t opcode;
+ uint32_t sequence;
+ string replyToKey;
+
+ if (msg.encodedSize() > MA_BUFFER_SIZE)
+ return false;
+
+ msg.encodeContent(inBuffer);
+ inBuffer.reset();
+
+ if (!checkHeader(inBuffer, &opcode, &sequence))
+ return false;
+
+ if (opcode == 'M') {
+ // TODO: check method call against ACL list.
+ AclModule* acl = broker->getAcl();
+ if (acl == 0)
+ return true;
+
+ string userId = ((const qpid::broker::ConnectionState*) msg.getPublisher())->getUserId();
+ string packageName;
+ string className;
+ uint8_t hash[16];
+ string methodName;
+
+ map<acl::Property, string> params;
+ ObjectId objId(inBuffer);
+ inBuffer.getShortString(packageName);
+ inBuffer.getShortString(className);
+ inBuffer.getBin128(hash);
+ inBuffer.getShortString(methodName);
+
+ params[acl::PROP_SCHEMAPACKAGE] = packageName;
+ params[acl::PROP_SCHEMACLASS] = className;
+
+ if (acl->authorise(userId, acl::ACT_ACCESS, acl::OBJ_METHOD, methodName, &params))
+ return true;
+
+ const framing::MessageProperties* p =
+ msg.getFrames().getHeaders()->get<framing::MessageProperties>();
+ if (p && p->hasReplyTo()) {
+ const framing::ReplyTo& rt = p->getReplyTo();
+ replyToKey = rt.getRoutingKey();
+
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ encodeHeader(outBuffer, 'm', sequence);
+ outBuffer.putLong(Manageable::STATUS_FORBIDDEN);
+ outBuffer.putMediumString(Manageable::StatusText(Manageable::STATUS_FORBIDDEN));
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
+ outBuffer.reset();
+ sendBuffer(outBuffer, outLen, dExchange, replyToKey);
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+void ManagementBroker::dispatchAgentCommandLH(Message& msg)
+{
+ Buffer inBuffer(inputBuffer, MA_BUFFER_SIZE);
+ uint8_t opcode;
+ uint32_t sequence;
+ string replyToKey;
+
+ const framing::MessageProperties* p =
+ msg.getFrames().getHeaders()->get<framing::MessageProperties>();
+ if (p && p->hasReplyTo()) {
+ const framing::ReplyTo& rt = p->getReplyTo();
+ replyToKey = rt.getRoutingKey();
+ }
+ else
+ return;
+
+ if (msg.encodedSize() > MA_BUFFER_SIZE) {
+ QPID_LOG(debug, "ManagementBroker::dispatchAgentCommandLH: Message too large: " <<
+ msg.encodedSize());
+ return;
+ }
+
+ msg.encodeContent(inBuffer);
+ uint32_t bufferLen = inBuffer.getPosition();
+ inBuffer.reset();
+
+ while (inBuffer.getPosition() < bufferLen) {
+ if (!checkHeader(inBuffer, &opcode, &sequence))
+ return;
+
+ if (opcode == 'B') handleBrokerRequestLH (inBuffer, replyToKey, sequence);
+ else if (opcode == 'P') handlePackageQueryLH (inBuffer, replyToKey, sequence);
+ else if (opcode == 'p') handlePackageIndLH (inBuffer, replyToKey, sequence);
+ else if (opcode == 'Q') handleClassQueryLH (inBuffer, replyToKey, sequence);
+ else if (opcode == 'q') handleClassIndLH (inBuffer, replyToKey, sequence);
+ else if (opcode == 'S') handleSchemaRequestLH (inBuffer, replyToKey, sequence);
+ else if (opcode == 's') handleSchemaResponseLH (inBuffer, replyToKey, sequence);
+ else if (opcode == 'A') handleAttachRequestLH (inBuffer, replyToKey, sequence, msg.getPublisher());
+ else if (opcode == 'G') handleGetQueryLH (inBuffer, replyToKey, sequence);
+ else if (opcode == 'M') handleMethodRequestLH (inBuffer, replyToKey, sequence, msg.getPublisher());
+ }
+}
+
+ManagementBroker::PackageMap::iterator ManagementBroker::findOrAddPackageLH(string name)
+{
+ PackageMap::iterator pIter = packages.find (name);
+ if (pIter != packages.end ())
+ return pIter;
+
+ // No such package found, create a new map entry.
+ pair<PackageMap::iterator, bool> result =
+ packages.insert(pair<string, ClassMap>(name, ClassMap()));
+ QPID_LOG (debug, "ManagementBroker added package " << name);
+
+ // Publish a package-indication message
+ Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ encodeHeader (outBuffer, 'p');
+ encodePackageIndication (outBuffer, result.first);
+ outLen = MA_BUFFER_SIZE - outBuffer.available ();
+ outBuffer.reset ();
+ sendBuffer (outBuffer, outLen, mExchange, "schema.package");
+
+ return result.first;
+}
+
+void ManagementBroker::addClassLH(uint8_t kind,
+ PackageMap::iterator pIter,
+ const string& className,
+ uint8_t* md5Sum,
+ ManagementObject::writeSchemaCall_t schemaCall)
+{
+ SchemaClassKey key;
+ ClassMap& cMap = pIter->second;
+
+ key.name = className;
+ memcpy(&key.hash, md5Sum, 16);
+
+ ClassMap::iterator cIter = cMap.find(key);
+ if (cIter != cMap.end())
+ return;
+
+ // No such class found, create a new class with local information.
+ QPID_LOG (debug, "ManagementBroker added class " << pIter->first << ":" <<
+ key.name);
+
+ cMap.insert(pair<SchemaClassKey, SchemaClass>(key, SchemaClass(kind, schemaCall)));
+ cIter = cMap.find(key);
+}
+
+void ManagementBroker::encodePackageIndication(Buffer& buf,
+ PackageMap::iterator pIter)
+{
+ buf.putShortString((*pIter).first);
+}
+
+void ManagementBroker::encodeClassIndication(Buffer& buf,
+ PackageMap::iterator pIter,
+ ClassMap::iterator cIter)
+{
+ SchemaClassKey key = (*cIter).first;
+
+ buf.putOctet((*cIter).second.kind);
+ buf.putShortString((*pIter).first);
+ buf.putShortString(key.name);
+ buf.putBin128(key.hash);
+}
+
+size_t ManagementBroker::validateSchema(Buffer& inBuffer, uint8_t kind)
+{
+ if (kind == ManagementItem::CLASS_KIND_TABLE)
+ return validateTableSchema(inBuffer);
+ else if (kind == ManagementItem::CLASS_KIND_EVENT)
+ return validateEventSchema(inBuffer);
+ return 0;
+}
+
+size_t ManagementBroker::validateTableSchema(Buffer& inBuffer)
+{
+ uint32_t start = inBuffer.getPosition();
+ uint32_t end;
+ string text;
+ uint8_t hash[16];
+
+ try {
+ inBuffer.record();
+ uint8_t kind = inBuffer.getOctet();
+ if (kind != ManagementItem::CLASS_KIND_TABLE)
+ return 0;
+
+ inBuffer.getShortString(text);
+ inBuffer.getShortString(text);
+ inBuffer.getBin128(hash);
+
+ uint16_t propCount = inBuffer.getShort();
+ uint16_t statCount = inBuffer.getShort();
+ uint16_t methCount = inBuffer.getShort();
+
+ for (uint16_t idx = 0; idx < propCount + statCount; idx++) {
+ FieldTable ft;
+ ft.decode(inBuffer);
+ }
+
+ for (uint16_t idx = 0; idx < methCount; idx++) {
+ FieldTable ft;
+ ft.decode(inBuffer);
+ if (!ft.isSet("argCount"))
+ return 0;
+ int argCount = ft.getAsInt("argCount");
+ for (int mIdx = 0; mIdx < argCount; mIdx++) {
+ FieldTable aft;
+ aft.decode(inBuffer);
+ }
+ }
+ } catch (exception& /*e*/) {
+ return 0;
+ }
+
+ end = inBuffer.getPosition();
+ inBuffer.restore(); // restore original position
+ return end - start;
+}
+
+size_t ManagementBroker::validateEventSchema(Buffer& inBuffer)
+{
+ uint32_t start = inBuffer.getPosition();
+ uint32_t end;
+ string text;
+ uint8_t hash[16];
+
+ try {
+ inBuffer.record();
+ uint8_t kind = inBuffer.getOctet();
+ if (kind != ManagementItem::CLASS_KIND_EVENT)
+ return 0;
+
+ inBuffer.getShortString(text);
+ inBuffer.getShortString(text);
+ inBuffer.getBin128(hash);
+
+ uint16_t argCount = inBuffer.getShort();
+
+ for (uint16_t idx = 0; idx < argCount; idx++) {
+ FieldTable ft;
+ ft.decode(inBuffer);
+ }
+ } catch (exception& /*e*/) {
+ return 0;
+ }
+
+ end = inBuffer.getPosition();
+ inBuffer.restore(); // restore original position
+ return end - start;
+}
diff --git a/RC9/qpid/cpp/src/qpid/management/ManagementBroker.h b/RC9/qpid/cpp/src/qpid/management/ManagementBroker.h
new file mode 100644
index 0000000000..59dfb98596
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/management/ManagementBroker.h
@@ -0,0 +1,235 @@
+#ifndef _ManagementBroker_
+#define _ManagementBroker_
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/Options.h"
+#include "qpid/broker/Exchange.h"
+#include "qpid/broker/Timer.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/broker/ConnectionToken.h"
+#include "qpid/agent/ManagementAgent.h"
+#include "ManagementObject.h"
+#include "Manageable.h"
+#include "qmf/org/apache/qpid/broker/Agent.h"
+#include <qpid/framing/AMQFrame.h>
+
+namespace qpid {
+namespace management {
+
+class ManagementBroker : public ManagementAgent
+{
+private:
+
+ int threadPoolSize;
+
+public:
+
+ ManagementBroker ();
+ virtual ~ManagementBroker ();
+
+ void configure (const std::string& dataDir, uint16_t interval,
+ qpid::broker::Broker* broker, int threadPoolSize);
+ void setInterval (uint16_t _interval) { interval = _interval; }
+ void setExchange (qpid::broker::Exchange::shared_ptr mgmtExchange,
+ qpid::broker::Exchange::shared_ptr directExchange);
+ int getMaxThreads () { return threadPoolSize; }
+ void registerClass (const std::string& packageName,
+ const std::string& className,
+ uint8_t* md5Sum,
+ ManagementObject::writeSchemaCall_t schemaCall);
+ void registerEvent (const std::string& packageName,
+ const std::string& eventName,
+ uint8_t* md5Sum,
+ ManagementObject::writeSchemaCall_t schemaCall);
+ ObjectId addObject (ManagementObject* object,
+ uint64_t persistId = 0);
+ void raiseEvent(const ManagementEvent& event, severity_t severity = SEV_DEFAULT);
+ void clientAdded (const std::string& routingKey);
+ bool dispatchCommand (qpid::broker::Deliverable& msg,
+ const std::string& routingKey,
+ const framing::FieldTable* args);
+ const framing::Uuid& getUuid() const { return uuid; }
+
+ // Stubs for remote management agent calls
+ void init(const std::string&, uint16_t, uint16_t, bool,
+ const std::string&, const std::string&, const std::string&,
+ const std::string&, const std::string&) { assert(0); }
+ void init(const client::ConnectionSettings&, uint16_t, bool, const std::string&) { assert(0); }
+ uint32_t pollCallbacks (uint32_t) { assert(0); return 0; }
+ int getSignalFd () { assert(0); return -1; }
+
+private:
+ friend class ManagementAgent;
+
+ struct Periodic : public qpid::broker::TimerTask
+ {
+ ManagementBroker& broker;
+
+ Periodic (ManagementBroker& broker, uint32_t seconds);
+ virtual ~Periodic ();
+ void fire ();
+ };
+
+ // Storage for tracking remote management agents, attached via the client
+ // management agent API.
+ //
+ struct RemoteAgent : public Manageable
+ {
+ uint32_t brokerBank;
+ uint32_t agentBank;
+ std::string routingKey;
+ ObjectId connectionRef;
+ qmf::org::apache::qpid::broker::Agent* mgmtObject;
+ ManagementObject* GetManagementObject (void) const { return mgmtObject; }
+ virtual ~RemoteAgent ();
+ };
+
+ // TODO: Eventually replace string with entire reply-to structure. reply-to
+ // currently assumes that the exchange is "amq.direct" even though it could
+ // in theory be specified differently.
+ typedef std::map<ObjectId, RemoteAgent*> RemoteAgentMap;
+ typedef std::vector<std::string> ReplyToVector;
+
+ // Storage for known schema classes:
+ //
+ // SchemaClassKey -- Key elements for map lookups
+ // SchemaClassKeyComp -- Comparison class for SchemaClassKey
+ // SchemaClass -- Non-key elements for classes
+ //
+ struct SchemaClassKey
+ {
+ std::string name;
+ uint8_t hash[16];
+ };
+
+ struct SchemaClassKeyComp
+ {
+ bool operator() (const SchemaClassKey& lhs, const SchemaClassKey& rhs) const
+ {
+ if (lhs.name != rhs.name)
+ return lhs.name < rhs.name;
+ else
+ for (int i = 0; i < 16; i++)
+ if (lhs.hash[i] != rhs.hash[i])
+ return lhs.hash[i] < rhs.hash[i];
+ return false;
+ }
+ };
+
+ struct SchemaClass
+ {
+ uint8_t kind;
+ ManagementObject::writeSchemaCall_t writeSchemaCall;
+ uint32_t pendingSequence;
+ size_t bufferLen;
+ uint8_t* buffer;
+
+ SchemaClass(uint8_t _kind, uint32_t seq) :
+ kind(_kind), writeSchemaCall(0), pendingSequence(seq), bufferLen(0), buffer(0) {}
+ SchemaClass(uint8_t _kind, ManagementObject::writeSchemaCall_t call) :
+ kind(_kind), writeSchemaCall(call), pendingSequence(0), bufferLen(0), buffer(0) {}
+ bool hasSchema () { return (writeSchemaCall != 0) || (buffer != 0); }
+ void appendSchema (framing::Buffer& buf);
+ };
+
+ typedef std::map<SchemaClassKey, SchemaClass, SchemaClassKeyComp> ClassMap;
+ typedef std::map<std::string, ClassMap> PackageMap;
+
+ RemoteAgentMap remoteAgents;
+ PackageMap packages;
+ ManagementObjectMap managementObjects;
+ ManagementObjectMap newManagementObjects;
+
+ static ManagementAgent* agent;
+ static bool enabled;
+
+ framing::Uuid uuid;
+ sys::Mutex addLock;
+ sys::Mutex userLock;
+ qpid::broker::Timer timer;
+ qpid::broker::Exchange::shared_ptr mExchange;
+ qpid::broker::Exchange::shared_ptr dExchange;
+ std::string dataDir;
+ uint16_t interval;
+ qpid::broker::Broker* broker;
+ uint16_t bootSequence;
+ uint32_t nextObjectId;
+ uint32_t brokerBank;
+ uint32_t nextRemoteBank;
+ uint32_t nextRequestSequence;
+ bool clientWasAdded;
+
+# define MA_BUFFER_SIZE 65536
+ char inputBuffer[MA_BUFFER_SIZE];
+ char outputBuffer[MA_BUFFER_SIZE];
+ char eventBuffer[MA_BUFFER_SIZE];
+
+ void writeData ();
+ void periodicProcessing (void);
+ void encodeHeader (framing::Buffer& buf, uint8_t opcode, uint32_t seq = 0);
+ bool checkHeader (framing::Buffer& buf, uint8_t *opcode, uint32_t *seq);
+ void sendBuffer (framing::Buffer& buf,
+ uint32_t length,
+ qpid::broker::Exchange::shared_ptr exchange,
+ std::string routingKey);
+ void moveNewObjectsLH();
+
+ bool authorizeAgentMessageLH(qpid::broker::Message& msg);
+ void dispatchAgentCommandLH(qpid::broker::Message& msg);
+
+ PackageMap::iterator findOrAddPackageLH(std::string name);
+ void addClassLH(uint8_t kind,
+ PackageMap::iterator pIter,
+ const std::string& className,
+ uint8_t* md5Sum,
+ ManagementObject::writeSchemaCall_t schemaCall);
+ void encodePackageIndication (framing::Buffer& buf,
+ PackageMap::iterator pIter);
+ void encodeClassIndication (framing::Buffer& buf,
+ PackageMap::iterator pIter,
+ ClassMap::iterator cIter);
+ bool bankInUse (uint32_t bank);
+ uint32_t allocateNewBank ();
+ uint32_t assignBankLH (uint32_t requestedPrefix);
+ void deleteOrphanedAgentsLH();
+ void sendCommandComplete (std::string replyToKey, uint32_t sequence,
+ uint32_t code = 0, std::string text = std::string("OK"));
+ void handleBrokerRequestLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
+ void handlePackageQueryLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
+ void handlePackageIndLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
+ void handleClassQueryLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
+ void handleClassIndLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
+ void handleSchemaRequestLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
+ void handleSchemaResponseLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
+ void handleAttachRequestLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence, const qpid::broker::ConnectionToken* connToken);
+ void handleGetQueryLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
+ void handleMethodRequestLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence, const qpid::broker::ConnectionToken* connToken);
+
+ size_t validateSchema(framing::Buffer&, uint8_t kind);
+ size_t validateTableSchema(framing::Buffer&);
+ size_t validateEventSchema(framing::Buffer&);
+};
+
+}}
+
+#endif /*!_ManagementBroker_*/
diff --git a/RC9/qpid/cpp/src/qpid/management/ManagementEvent.h b/RC9/qpid/cpp/src/qpid/management/ManagementEvent.h
new file mode 100644
index 0000000000..8566f31c47
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/management/ManagementEvent.h
@@ -0,0 +1,49 @@
+#ifndef _ManagementEvent_
+#define _ManagementEvent_
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "ManagementObject.h"
+#include <qpid/framing/Buffer.h>
+#include <string>
+
+namespace qpid {
+namespace management {
+
+class ManagementAgent;
+
+class ManagementEvent : public ManagementItem {
+public:
+ typedef void (*writeSchemaCall_t)(qpid::framing::Buffer&);
+ virtual ~ManagementEvent() {}
+
+ virtual writeSchemaCall_t getWriteSchemaCall(void) = 0;
+ virtual std::string& getEventName() const = 0;
+ virtual std::string& getPackageName() const = 0;
+ virtual uint8_t* getMd5Sum() const = 0;
+ virtual uint8_t getSeverity() const = 0;
+ virtual void encode(qpid::framing::Buffer&) const = 0;
+};
+
+}}
+
+#endif /*!_ManagementEvent_*/
diff --git a/RC9/qpid/cpp/src/qpid/management/ManagementExchange.cpp b/RC9/qpid/cpp/src/qpid/management/ManagementExchange.cpp
new file mode 100644
index 0000000000..4dcafbfcdd
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/management/ManagementExchange.cpp
@@ -0,0 +1,72 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "ManagementExchange.h"
+#include "qpid/log/Statement.h"
+
+using namespace qpid::management;
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+ManagementExchange::ManagementExchange (const string& _name, Manageable* _parent) :
+ Exchange (_name, _parent), TopicExchange(_name, _parent) {}
+ManagementExchange::ManagementExchange (const std::string& _name,
+ bool _durable,
+ const FieldTable& _args,
+ Manageable* _parent) :
+ Exchange (_name, _durable, _args, _parent),
+ TopicExchange(_name, _durable, _args, _parent) {}
+
+void ManagementExchange::route (Deliverable& msg,
+ const string& routingKey,
+ const FieldTable* args)
+{
+ bool routeIt = true;
+
+ // Intercept management agent commands
+ if ((routingKey.length() > 6 &&
+ routingKey.substr(0, 6).compare("agent.") == 0) ||
+ (routingKey == "broker"))
+ routeIt = managementAgent->dispatchCommand(msg, routingKey, args);
+
+ if (routeIt)
+ TopicExchange::route(msg, routingKey, args);
+}
+
+bool ManagementExchange::bind (Queue::shared_ptr queue,
+ const string& routingKey,
+ const qpid::framing::FieldTable* args)
+{
+ managementAgent->clientAdded(routingKey);
+ return TopicExchange::bind(queue, routingKey, args);
+}
+
+void ManagementExchange::setManagmentAgent (ManagementBroker* agent)
+{
+ managementAgent = agent;
+}
+
+
+ManagementExchange::~ManagementExchange() {}
+
+const std::string ManagementExchange::typeName("management");
+
diff --git a/RC9/qpid/cpp/src/qpid/management/ManagementExchange.h b/RC9/qpid/cpp/src/qpid/management/ManagementExchange.h
new file mode 100644
index 0000000000..d54db1a74e
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/management/ManagementExchange.h
@@ -0,0 +1,62 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _ManagementExchange_
+#define _ManagementExchange_
+
+#include "qpid/broker/TopicExchange.h"
+#include "ManagementBroker.h"
+
+namespace qpid {
+namespace broker {
+
+class ManagementExchange : public virtual TopicExchange
+{
+ private:
+ management::ManagementBroker* managementAgent;
+
+ public:
+ static const std::string typeName;
+
+ ManagementExchange (const string& name, Manageable* _parent = 0);
+ ManagementExchange (const string& _name, bool _durable,
+ const qpid::framing::FieldTable& _args,
+ Manageable* _parent = 0);
+
+ virtual std::string getType() const { return typeName; }
+
+ virtual void route (Deliverable& msg,
+ const string& routingKey,
+ const qpid::framing::FieldTable* args);
+
+ virtual bool bind (Queue::shared_ptr queue,
+ const string& routingKey,
+ const qpid::framing::FieldTable* args);
+
+ void setManagmentAgent (management::ManagementBroker* agent);
+
+ virtual ~ManagementExchange();
+};
+
+
+}
+}
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/management/ManagementObject.cpp b/RC9/qpid/cpp/src/qpid/management/ManagementObject.cpp
new file mode 100644
index 0000000000..f4c45de126
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/management/ManagementObject.cpp
@@ -0,0 +1,183 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Manageable.h"
+#include "ManagementObject.h"
+#include "qpid/agent/ManagementAgent.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/sys/Thread.h"
+
+#include <stdlib.h>
+
+using namespace qpid;
+using namespace qpid::management;
+
+void AgentAttachment::setBanks(uint32_t broker, uint32_t bank)
+{
+ first =
+ ((uint64_t) (broker & 0x000fffff)) << 28 |
+ ((uint64_t) (bank & 0x0fffffff));
+}
+
+ObjectId::ObjectId(uint8_t flags, uint16_t seq, uint32_t broker, uint32_t bank, uint64_t object)
+ : agent(0)
+{
+ first =
+ ((uint64_t) (flags & 0x0f)) << 60 |
+ ((uint64_t) (seq & 0x0fff)) << 48 |
+ ((uint64_t) (broker & 0x000fffff)) << 28 |
+ ((uint64_t) (bank & 0x0fffffff));
+ second = object;
+}
+
+ObjectId::ObjectId(AgentAttachment* _agent, uint8_t flags, uint16_t seq, uint64_t object)
+ : agent(_agent)
+{
+ first =
+ ((uint64_t) (flags & 0x0f)) << 60 |
+ ((uint64_t) (seq & 0x0fff)) << 48;
+ second = object;
+}
+
+ObjectId::ObjectId(std::istream& in) : agent(0)
+{
+ std::string text;
+ in >> text;
+ fromString(text);
+}
+
+ObjectId::ObjectId(const std::string& text) : agent(0)
+{
+ fromString(text);
+}
+
+void ObjectId::fromString(const std::string& text)
+{
+#define FIELDS 5
+#if defined (_WIN32) && !defined (atoll)
+# define atoll(X) _atoi64(X)
+#endif
+
+ std::string copy(text.c_str());
+ char* cText;
+ char* field[FIELDS];
+ bool atFieldStart = true;
+ int idx = 0;
+
+ cText = const_cast<char*>(copy.c_str());
+ for (char* cursor = cText; *cursor; cursor++) {
+ if (atFieldStart) {
+ if (idx >= FIELDS)
+ throw Exception("Invalid ObjectId format");
+ field[idx++] = cursor;
+ atFieldStart = false;
+ } else {
+ if (*cursor == '-') {
+ *cursor = '\0';
+ atFieldStart = true;
+ }
+ }
+ }
+
+ if (idx != FIELDS)
+ throw Exception("Invalid ObjectId format");
+
+ first = (atoll(field[0]) << 60) +
+ (atoll(field[1]) << 48) +
+ (atoll(field[2]) << 28) +
+ atoll(field[3]);
+ second = atoll(field[4]);
+}
+
+
+bool ObjectId::operator==(const ObjectId &other) const
+{
+ uint64_t otherFirst = agent == 0 ? other.first : other.first & 0xffff000000000000LL;
+
+ return first == otherFirst && second == other.second;
+}
+
+bool ObjectId::operator<(const ObjectId &other) const
+{
+ uint64_t otherFirst = agent == 0 ? other.first : other.first & 0xffff000000000000LL;
+
+ return (first < otherFirst) || ((first == otherFirst) && (second < other.second));
+}
+
+void ObjectId::encode(framing::Buffer& buffer)
+{
+ if (agent == 0)
+ buffer.putLongLong(first);
+ else
+ buffer.putLongLong(first | agent->first);
+ buffer.putLongLong(second);
+}
+
+void ObjectId::decode(framing::Buffer& buffer)
+{
+ first = buffer.getLongLong();
+ second = buffer.getLongLong();
+}
+
+namespace qpid {
+namespace management {
+
+std::ostream& operator<<(std::ostream& out, const ObjectId& i)
+{
+ uint64_t virtFirst = i.first;
+ if (i.agent)
+ virtFirst |= i.agent->getFirst();
+
+ out << ((virtFirst & 0xF000000000000000LL) >> 60) <<
+ "-" << ((virtFirst & 0x0FFF000000000000LL) >> 48) <<
+ "-" << ((virtFirst & 0x0000FFFFF0000000LL) >> 28) <<
+ "-" << (virtFirst & 0x000000000FFFFFFFLL) <<
+ "-" << i.second;
+ return out;
+}
+
+}}
+
+int ManagementObject::nextThreadIndex = 0;
+
+void ManagementObject::writeTimestamps (framing::Buffer& buf)
+{
+ buf.putShortString (getPackageName ());
+ buf.putShortString (getClassName ());
+ buf.putBin128 (getMd5Sum ());
+ buf.putLongLong (updateTime);
+ buf.putLongLong (createTime);
+ buf.putLongLong (destroyTime);
+ objectId.encode(buf);
+}
+
+void ManagementObject::setReference(ObjectId) {}
+
+int ManagementObject::getThreadIndex() {
+ static QPID_TSS int thisIndex = -1;
+ if (thisIndex == -1) {
+ sys::Mutex::ScopedLock mutex(accessLock);
+ thisIndex = nextThreadIndex;
+ if (nextThreadIndex < agent->getMaxThreads() - 1)
+ nextThreadIndex++;
+ }
+ return thisIndex;
+}
diff --git a/RC9/qpid/cpp/src/qpid/management/ManagementObject.h b/RC9/qpid/cpp/src/qpid/management/ManagementObject.h
new file mode 100644
index 0000000000..fbdad347b8
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/management/ManagementObject.h
@@ -0,0 +1,188 @@
+#ifndef _ManagementObject_
+#define _ManagementObject_
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Time.h"
+#include "qpid/sys/Mutex.h"
+#include <qpid/framing/Buffer.h>
+#include <map>
+
+namespace qpid {
+namespace management {
+
+class Manageable;
+class ManagementAgent;
+class ObjectId;
+
+
+class AgentAttachment {
+ friend class ObjectId;
+private:
+ uint64_t first;
+public:
+ AgentAttachment() : first(0) {}
+ void setBanks(uint32_t broker, uint32_t bank);
+ uint64_t getFirst() const { return first; }
+};
+
+
+class ObjectId {
+protected:
+ const AgentAttachment* agent;
+ uint64_t first;
+ uint64_t second;
+ void fromString(const std::string&);
+public:
+ ObjectId() : agent(0), first(0), second(0) {}
+ ObjectId(framing::Buffer& buf) : agent(0) { decode(buf); }
+ ObjectId(uint8_t flags, uint16_t seq, uint32_t broker, uint32_t bank, uint64_t object);
+ ObjectId(AgentAttachment* _agent, uint8_t flags, uint16_t seq, uint64_t object);
+ ObjectId(std::istream&);
+ ObjectId(const std::string&);
+ bool operator==(const ObjectId &other) const;
+ bool operator<(const ObjectId &other) const;
+ void encode(framing::Buffer& buffer);
+ void decode(framing::Buffer& buffer);
+ friend std::ostream& operator<<(std::ostream&, const ObjectId&);
+};
+
+class ManagementItem {
+public:
+ static const uint8_t TYPE_U8 = 1;
+ static const uint8_t TYPE_U16 = 2;
+ static const uint8_t TYPE_U32 = 3;
+ static const uint8_t TYPE_U64 = 4;
+ static const uint8_t TYPE_SSTR = 6;
+ static const uint8_t TYPE_LSTR = 7;
+ static const uint8_t TYPE_ABSTIME = 8;
+ static const uint8_t TYPE_DELTATIME = 9;
+ static const uint8_t TYPE_REF = 10;
+ static const uint8_t TYPE_BOOL = 11;
+ static const uint8_t TYPE_FLOAT = 12;
+ static const uint8_t TYPE_DOUBLE = 13;
+ static const uint8_t TYPE_UUID = 14;
+ static const uint8_t TYPE_FTABLE = 15;
+ static const uint8_t TYPE_S8 = 16;
+ static const uint8_t TYPE_S16 = 17;
+ static const uint8_t TYPE_S32 = 18;
+ static const uint8_t TYPE_S64 = 19;
+
+ static const uint8_t ACCESS_RC = 1;
+ static const uint8_t ACCESS_RW = 2;
+ static const uint8_t ACCESS_RO = 3;
+
+ static const uint8_t DIR_I = 1;
+ static const uint8_t DIR_O = 2;
+ static const uint8_t DIR_IO = 3;
+
+ static const uint8_t FLAG_CONFIG = 0x01;
+ static const uint8_t FLAG_INDEX = 0x02;
+ static const uint8_t FLAG_END = 0x80;
+
+ const static uint8_t CLASS_KIND_TABLE = 1;
+ const static uint8_t CLASS_KIND_EVENT = 2;
+
+
+
+public:
+ virtual ~ManagementItem() {}
+};
+
+class ManagementObject : public ManagementItem
+{
+ protected:
+
+ uint64_t createTime;
+ uint64_t destroyTime;
+ uint64_t updateTime;
+ ObjectId objectId;
+ bool configChanged;
+ bool instChanged;
+ bool deleted;
+ Manageable* coreObject;
+ sys::Mutex accessLock;
+ ManagementAgent* agent;
+ int maxThreads;
+ uint32_t flags;
+
+ static int nextThreadIndex;
+ bool forcePublish;
+
+ int getThreadIndex();
+ void writeTimestamps(qpid::framing::Buffer& buf);
+
+ public:
+ typedef void (*writeSchemaCall_t) (qpid::framing::Buffer&);
+
+ ManagementObject(ManagementAgent* _agent, Manageable* _core) :
+ createTime(uint64_t(qpid::sys::Duration(qpid::sys::now()))),
+ destroyTime(0), updateTime(createTime), configChanged(true),
+ instChanged(true), deleted(false),
+ coreObject(_core), agent(_agent), forcePublish(false) {}
+ virtual ~ManagementObject() {}
+
+ virtual writeSchemaCall_t getWriteSchemaCall() = 0;
+ virtual void writeProperties(qpid::framing::Buffer& buf) = 0;
+ virtual void writeStatistics(qpid::framing::Buffer& buf,
+ bool skipHeaders = false) = 0;
+ virtual void doMethod(std::string& methodName,
+ qpid::framing::Buffer& inBuf,
+ qpid::framing::Buffer& outBuf) = 0;
+ virtual void setReference(ObjectId objectId);
+
+ virtual std::string& getClassName() const = 0;
+ virtual std::string& getPackageName() const = 0;
+ virtual uint8_t* getMd5Sum() const = 0;
+
+ void setObjectId(ObjectId oid) { objectId = oid; }
+ ObjectId getObjectId() { return objectId; }
+ inline bool getConfigChanged() { return configChanged; }
+ virtual bool getInstChanged() { return instChanged; }
+ virtual bool hasInst() { return true; }
+ inline void setForcePublish(bool f) { forcePublish = f; }
+ inline bool getForcePublish() { return forcePublish; }
+ inline void setUpdateTime() { updateTime = (uint64_t(sys::Duration(sys::now()))); }
+
+ inline void resourceDestroy() {
+ destroyTime = uint64_t (qpid::sys::Duration(qpid::sys::now()));
+ deleted = true;
+ }
+ inline bool isDeleted() { return deleted; }
+ inline void setFlags(uint32_t f) { flags = f; }
+ inline uint32_t getFlags() { return flags; }
+ bool isSameClass(ManagementObject& other) {
+ for (int idx = 0; idx < 16; idx++)
+ if (other.getMd5Sum()[idx] != getMd5Sum()[idx])
+ return false;
+ return other.getClassName() == getClassName() &&
+ other.getPackageName() == getPackageName();
+ }
+};
+
+typedef std::map<ObjectId, ManagementObject*> ManagementObjectMap;
+
+}}
+
+
+
+#endif /*!_ManagementObject_*/
diff --git a/RC9/qpid/cpp/src/qpid/memory.h b/RC9/qpid/cpp/src/qpid/memory.h
new file mode 100644
index 0000000000..99d7a71e7b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/memory.h
@@ -0,0 +1,32 @@
+#ifndef QPID_AUTO_PTR_H
+#define QPID_AUTO_PTR_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <memory>
+namespace qpid {
+/** Convenient template for creating auto_ptr in-place in an argument list. */
+template <class T>
+std::auto_ptr<T> make_auto_ptr(T* ptr) { return std::auto_ptr<T>(ptr); }
+
+} // namespace qpid
+
+
+
+#endif /*!QPID_AUTO_PTR_H*/
diff --git a/RC9/qpid/cpp/src/qpid/pointer_to_other.h b/RC9/qpid/cpp/src/qpid/pointer_to_other.h
new file mode 100644
index 0000000000..a99dc89658
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/pointer_to_other.h
@@ -0,0 +1,62 @@
+#ifndef QPID_POINTERTOOTHER_H
+#define QPID_POINTERTOOTHER_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+namespace qpid {
+
+// Defines the same pointer type (raw or smart) to another pointee type
+
+template<class T, class U>
+struct pointer_to_other;
+
+template<class T, class U,
+ template<class> class Sp>
+struct pointer_to_other< Sp<T>, U >
+ {
+ typedef Sp<U> type;
+ };
+
+template<class T, class T2, class U,
+ template<class, class> class Sp>
+struct pointer_to_other< Sp<T, T2>, U >
+ {
+ typedef Sp<U, T2> type;
+ };
+
+template<class T, class T2, class T3, class U,
+ template<class, class, class> class Sp>
+struct pointer_to_other< Sp<T, T2, T3>, U >
+ {
+ typedef Sp<U, T2, T3> type;
+ };
+
+template<class T, class U>
+struct pointer_to_other< T*, U >
+{
+ typedef U* type;
+};
+
+} // namespace qpid
+
+
+
+#endif /*!QPID_POINTERTOOTHER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/ptr_map.h b/RC9/qpid/cpp/src/qpid/ptr_map.h
new file mode 100644
index 0000000000..6ffcd48e89
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/ptr_map.h
@@ -0,0 +1,57 @@
+#ifndef QPID_PTR_MAP
+#define QPID_PTR_MAP
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <boost/ptr_container/ptr_map.hpp>
+#include <boost/utility/enable_if.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <boost/type_traits/remove_const.hpp>
+
+namespace qpid {
+
+/** @file
+ * Workaround for API change between boost 1.33 and 1.34.
+ *
+ * To be portable across these versions, code using boost::ptr_map
+ * iterators should use ptr_map_ptr(i) to get the pointer from
+ * boost::ptr_map::iterator i.
+ *
+ * @see http://www.boost.org/libs/ptr_container/doc/ptr_container.html#upgrading-from-boost-v-1-33
+ */
+
+
+typedef boost::is_same<boost::ptr_map<int, int>::iterator::value_type, int> IsOldPtrMap;
+
+template <class Iter>
+typename boost::enable_if<IsOldPtrMap, typename Iter::value_type*>::type
+ptr_map_ptr(const Iter& i) { return &*i; }
+
+template <class Iter>
+typename boost::disable_if<IsOldPtrMap,
+ typename boost::remove_const<typename Iter::value_type::second_type>::type
+ >::type
+ptr_map_ptr(const Iter& i) { return i->second; }
+
+} // namespace qpid
+
+#endif /*!QPID_PTR_MAP*/
diff --git a/RC9/qpid/cpp/src/qpid/shared_ptr.h b/RC9/qpid/cpp/src/qpid/shared_ptr.h
new file mode 100644
index 0000000000..0c933ea6a6
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/shared_ptr.h
@@ -0,0 +1,51 @@
+#ifndef _common_shared_ptr_h
+#define _common_shared_ptr_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <boost/shared_ptr.hpp>
+#include <boost/cast.hpp>
+
+namespace qpid {
+
+// Import shared_ptr definitions into qpid namespace and define some
+// useful shared_ptr templates for convenience.
+
+using boost::shared_ptr;
+using boost::dynamic_pointer_cast;
+using boost::static_pointer_cast;
+using boost::const_pointer_cast;
+using boost::shared_polymorphic_downcast;
+
+template <class T> shared_ptr<T> make_shared_ptr(T* ptr) {
+ return shared_ptr<T>(ptr);
+}
+
+template <class T, class D>
+shared_ptr<T> make_shared_ptr(T* ptr, D deleter) {
+ return shared_ptr<T>(ptr, deleter);
+}
+
+inline void nullDeleter(void const *) {}
+
+} // namespace qpid
+
+
+
+#endif /*!_common_shared_ptr_h*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/ActivityTimer.h b/RC9/qpid/cpp/src/qpid/sys/ActivityTimer.h
new file mode 100644
index 0000000000..d49e16bc4f
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/ActivityTimer.h
@@ -0,0 +1,106 @@
+#ifndef QPID_SYS_ACTIVITYTIMER_H
+#define QPID_SYS_ACTIVITYTIMER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Time.h"
+#include "qpid/sys/Thread.h"
+#include <boost/current_function.hpp>
+#include <stdio.h>
+
+namespace qpid {
+namespace sys {
+
+/**
+ * Measures and reports time spent in a particular segment of code.
+ * This is real time so it includes time blocked/sleeping as well as time on CPU.
+ *
+ * Intended to be used via the QPID_ACTIVITY_TIMER macro for profiling
+ * during development & debugging
+ */
+class ActivityTimer
+{
+ public:
+
+ struct Stat { // Must be a POD
+ uint64_t total, count;
+ void sample(uint64_t value) { total += value; ++count; }
+ uint64_t mean() { return count ? total/count : 0; }
+ void reset() { total = count = 0; }
+ };
+
+ struct Data { // Must be a POD
+ uint64_t start, entered;
+ Stat active;
+
+ void reset() {
+ start = entered = 0;
+ active.reset();
+ }
+
+ void enter(uint64_t now) {
+ entered=now;
+ if (!start) start = Duration(now);
+ }
+
+ void exit(uint64_t now) {
+ active.sample(now - entered);
+ }
+ };
+
+ ActivityTimer(Data& d, const char* fn, const char* file, int line, uint64_t reportInterval) : data(d) {
+ uint64_t now = Duration(qpid::sys::now());
+ if (data.start) {
+ interval = now-data.start;
+ if (interval > reportInterval)
+ report(fn, file, line);
+ }
+ data.enter(now);
+ }
+
+ ~ActivityTimer() {
+ data.exit(Duration(now()));
+ }
+
+ private:
+ Data& data;
+ uint64_t interval;
+
+ void report(const char* fn, const char* file, int line) {
+ long rate = (data.active.count*TIME_SEC)/interval;
+ double percent = (data.active.total*100.0)/interval;
+ printf("%s:%d: TIMER %ld/sec %f%% [%lu] %s\n",
+ file, line, rate, percent, Thread::current().id(), fn);
+ data.reset();
+ }
+};
+
+}} // namespace qpid::sys
+
+/** Measures time between the point of declaration and the end of the innermost enclosing scope.
+ * Can only have one in a given scope.
+ */
+#define ACTIVITY_TIMER(REPORT_INTERVAL_SECS) \
+ static __thread ::qpid::sys::ActivityTimer::Data qpid__ActivityTimerData__ = { 0, 0, { 0,0 }}; \
+ ::qpid::sys::ActivityTimer qpid__ActivityTimerInstance__(qpid__ActivityTimerData__, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__, 2*::qpid::sys::TIME_SEC)
+
+#endif /*!QPID_SYS_ACTIVITYTIMER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/AggregateOutput.cpp b/RC9/qpid/cpp/src/qpid/sys/AggregateOutput.cpp
new file mode 100644
index 0000000000..fa6901d3e4
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/AggregateOutput.cpp
@@ -0,0 +1,73 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/AggregateOutput.h"
+#include "qpid/log/Statement.h"
+#include <algorithm>
+
+namespace qpid {
+namespace sys {
+
+void AggregateOutput::activateOutput() { control.activateOutput(); }
+
+void AggregateOutput::giveReadCredit(int32_t credit) { control.giveReadCredit(credit); }
+
+bool AggregateOutput::hasOutput() {
+ for (TaskList::const_iterator i = tasks.begin(); i != tasks.end(); ++i)
+ if ((*i)->hasOutput()) return true;
+ return false;
+}
+
+bool AggregateOutput::doOutput()
+{
+ bool result = false;
+ if (!tasks.empty()) {
+ if (next >= tasks.size()) next = next % tasks.size();
+
+ size_t start = next;
+ //loop until a task generated some output
+ while (!result) {
+ result = tasks[next++]->doOutput();
+ if (tasks.empty()) break;
+ if (next >= tasks.size()) next = next % tasks.size();
+ if (start == next) break;
+ }
+ }
+ return result;
+}
+
+void AggregateOutput::addOutputTask(OutputTask* t)
+{
+ tasks.push_back(t);
+}
+
+void AggregateOutput::removeOutputTask(OutputTask* t)
+{
+ TaskList::iterator i = std::find(tasks.begin(), tasks.end(), t);
+ if (i != tasks.end()) tasks.erase(i);
+}
+
+void AggregateOutput::removeAll()
+{
+ tasks.clear();
+}
+
+}} // namespace qpid::sys
diff --git a/RC9/qpid/cpp/src/qpid/sys/AggregateOutput.h b/RC9/qpid/cpp/src/qpid/sys/AggregateOutput.h
new file mode 100644
index 0000000000..1cda4456b4
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/AggregateOutput.h
@@ -0,0 +1,65 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _AggregateOutput_
+#define _AggregateOutput_
+
+#include "Mutex.h"
+#include "OutputControl.h"
+#include "OutputTask.h"
+
+#include <algorithm>
+#include <vector>
+
+namespace qpid {
+namespace sys {
+
+ class AggregateOutput : public OutputTask, public OutputControl
+ {
+ typedef std::vector<OutputTask*> TaskList;
+
+ TaskList tasks;
+ size_t next;
+ OutputControl& control;
+
+ public:
+ AggregateOutput(OutputControl& c) : next(0), control(c) {};
+ //this may be called on any thread
+ void activateOutput();
+ void giveReadCredit(int32_t);
+
+ //all the following will be called on the same thread
+ bool doOutput();
+ bool hasOutput();
+ void addOutputTask(OutputTask* t);
+ void removeOutputTask(OutputTask* t);
+ void removeAll();
+
+ /** Apply f to each OutputTask* in the tasks list */
+ template <class F> void eachOutput(F f) {
+ std::for_each(tasks.begin(), tasks.end(), f);
+ }
+ };
+
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/sys/AsynchIO.h b/RC9/qpid/cpp/src/qpid/sys/AsynchIO.h
new file mode 100644
index 0000000000..68e441349a
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/AsynchIO.h
@@ -0,0 +1,152 @@
+#ifndef _sys_AsynchIO
+#define _sys_AsynchIO
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+// @@TODO: TAKE THIS OUT... SHould be in posix version.
+#include "DispatchHandle.h"
+
+#include <boost/function.hpp>
+#include <deque>
+
+namespace qpid {
+namespace sys {
+
+class Socket;
+
+/*
+ * Asynchronous acceptor: accepts connections then does a callback with the
+ * accepted fd
+ */
+class AsynchAcceptorPrivate;
+class AsynchAcceptor {
+public:
+ typedef boost::function1<void, const Socket&> Callback;
+
+private:
+ AsynchAcceptorPrivate* impl;
+
+public:
+ AsynchAcceptor(const Socket& s, Callback callback);
+ ~AsynchAcceptor();
+ void start(Poller::shared_ptr poller);
+};
+
+/*
+ * Asynchronous connector: starts the process of initiating a connection and
+ * invokes a callback when completed or failed.
+ */
+class AsynchConnector {
+public:
+ typedef boost::function1<void, const Socket&> ConnectedCallback;
+ typedef boost::function2<void, int, std::string> FailedCallback;
+
+ // Call create() to allocate a new AsynchConnector object with the
+ // specified poller, addressing, and callbacks.
+ // This method is implemented in platform-specific code to
+ // create a correctly typed object. The platform code also manages
+ // deletes. To correctly manage heaps when needed, the allocate and
+ // delete should both be done from the same class/library.
+ static AsynchConnector* create(const Socket& s,
+ Poller::shared_ptr poller,
+ std::string hostname,
+ uint16_t port,
+ ConnectedCallback connCb,
+ FailedCallback failCb = 0);
+
+protected:
+ AsynchConnector() {}
+ virtual ~AsynchConnector() {}
+};
+
+struct AsynchIOBufferBase {
+ char* const bytes;
+ const int32_t byteCount;
+ int32_t dataStart;
+ int32_t dataCount;
+
+ AsynchIOBufferBase(char* const b, const int32_t s) :
+ bytes(b),
+ byteCount(s),
+ dataStart(0),
+ dataCount(0)
+ {}
+
+ virtual ~AsynchIOBufferBase()
+ {}
+};
+
+/*
+ * Asychronous reader/writer:
+ * Reader accepts buffers to read into; reads into the provided buffers
+ * and then does a callback with the buffer and amount read. Optionally it
+ * can callback when there is something to read but no buffer to read it into.
+ *
+ * Writer accepts a buffer and queues it for writing; can also be given
+ * a callback for when writing is "idle" (ie fd is writable, but nothing
+ * to write).
+ */
+class AsynchIO {
+public:
+ typedef AsynchIOBufferBase BufferBase;
+
+ typedef boost::function2<bool, AsynchIO&, BufferBase*> ReadCallback;
+ typedef boost::function1<void, AsynchIO&> EofCallback;
+ typedef boost::function1<void, AsynchIO&> DisconnectCallback;
+ typedef boost::function2<void, AsynchIO&, const Socket&> ClosedCallback;
+ typedef boost::function1<void, AsynchIO&> BuffersEmptyCallback;
+ typedef boost::function1<void, AsynchIO&> IdleCallback;
+
+ // Call create() to allocate a new AsynchIO object with the specified
+ // callbacks. This method is implemented in platform-specific code to
+ // create a correctly typed object. The platform code also manages
+ // deletes. To correctly manage heaps when needed, the allocate and
+ // delete should both be done from the same class/library.
+ static AsynchIO* create(const Socket& s,
+ ReadCallback rCb,
+ EofCallback eofCb,
+ DisconnectCallback disCb,
+ ClosedCallback cCb = 0,
+ BuffersEmptyCallback eCb = 0,
+ IdleCallback iCb = 0);
+public:
+ virtual void queueForDeletion() = 0;
+
+ virtual void start(Poller::shared_ptr poller) = 0;
+ virtual void queueReadBuffer(BufferBase* buff) = 0;
+ virtual void unread(BufferBase* buff) = 0;
+ virtual void queueWrite(BufferBase* buff) = 0;
+ virtual void notifyPendingWrite() = 0;
+ virtual void queueWriteClose() = 0;
+ virtual bool writeQueueEmpty() = 0;
+ virtual void startReading() = 0;
+ virtual BufferBase* getQueuedBuffer() = 0;
+
+protected:
+ // Derived class manages lifetime; must be constructed using the
+ // static create() method. Deletes not allowed from outside.
+ AsynchIO() {}
+ virtual ~AsynchIO() {}
+};
+
+}}
+
+#endif // _sys_AsynchIO
diff --git a/RC9/qpid/cpp/src/qpid/sys/AsynchIOHandler.cpp b/RC9/qpid/cpp/src/qpid/sys/AsynchIOHandler.cpp
new file mode 100644
index 0000000000..83b6329889
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/AsynchIOHandler.cpp
@@ -0,0 +1,199 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "AsynchIOHandler.h"
+#include "qpid/sys/AsynchIO.h"
+#include "qpid/sys/Socket.h"
+#include "qpid/framing/AMQP_HighestVersion.h"
+#include "qpid/framing/ProtocolInitiation.h"
+#include "qpid/log/Statement.h"
+
+namespace qpid {
+namespace sys {
+
+// Buffer definition
+struct Buff : public AsynchIO::BufferBase {
+ Buff() :
+ AsynchIO::BufferBase(new char[65536], 65536)
+ {}
+ ~Buff()
+ { delete [] bytes;}
+};
+
+AsynchIOHandler::AsynchIOHandler(std::string id, ConnectionCodec::Factory* f) :
+ identifier(id),
+ aio(0),
+ factory(f),
+ codec(0),
+ readError(false),
+ isClient(false),
+ readCredit(InfiniteCredit)
+{}
+
+AsynchIOHandler::~AsynchIOHandler() {
+ if (codec)
+ codec->closed();
+ delete codec;
+}
+
+void AsynchIOHandler::init(AsynchIO* a, int numBuffs) {
+ aio = a;
+
+ // Give connection some buffers to use
+ for (int i = 0; i < numBuffs; i++) {
+ aio->queueReadBuffer(new Buff);
+ }
+}
+
+void AsynchIOHandler::write(const framing::ProtocolInitiation& data)
+{
+ QPID_LOG(debug, "SENT [" << identifier << "] INIT(" << data << ")");
+ AsynchIO::BufferBase* buff = aio->getQueuedBuffer();
+ if (!buff)
+ buff = new Buff;
+ framing::Buffer out(buff->bytes, buff->byteCount);
+ data.encode(out);
+ buff->dataCount = data.encodedSize();
+ aio->queueWrite(buff);
+}
+
+void AsynchIOHandler::activateOutput() {
+ aio->notifyPendingWrite();
+}
+
+// Input side
+void AsynchIOHandler::giveReadCredit(int32_t credit) {
+ // Check whether we started in the don't about credit state
+ if (readCredit.boolCompareAndSwap(InfiniteCredit, credit))
+ return;
+ else if (readCredit.fetchAndAdd(credit) != 0)
+ return;
+ // Lock and retest credit to make sure we don't race with decreasing credit
+ ScopedLock<Mutex> l(creditLock);
+ assert(readCredit.get() >= 0);
+ if (readCredit.get() != 0)
+ aio->startReading();
+}
+
+bool AsynchIOHandler::readbuff(AsynchIO& , AsynchIO::BufferBase* buff) {
+ if (readError) {
+ return false;
+ }
+ size_t decoded = 0;
+ if (codec) { // Already initiated
+ try {
+ decoded = codec->decode(buff->bytes+buff->dataStart, buff->dataCount);
+ }catch(const std::exception& e){
+ QPID_LOG(error, e.what());
+ readError = true;
+ aio->queueWriteClose();
+ }
+ }else{
+ framing::Buffer in(buff->bytes+buff->dataStart, buff->dataCount);
+ framing::ProtocolInitiation protocolInit;
+ if (protocolInit.decode(in)) {
+ decoded = in.getPosition();
+ QPID_LOG(debug, "RECV [" << identifier << "] INIT(" << protocolInit << ")");
+ try {
+ codec = factory->create(protocolInit.getVersion(), *this, identifier);
+ if (!codec) {
+ //TODO: may still want to revise this...
+ //send valid version header & close connection.
+ write(framing::ProtocolInitiation(framing::highestProtocolVersion));
+ readError = true;
+ aio->queueWriteClose();
+ }
+ } catch (const std::exception& e) {
+ QPID_LOG(error, e.what());
+ readError = true;
+ aio->queueWriteClose();
+ }
+ }
+ }
+ // TODO: unreading needs to go away, and when we can cope
+ // with multiple sub-buffers in the general buffer scheme, it will
+ if (decoded != size_t(buff->dataCount)) {
+ // Adjust buffer for used bytes and then "unread them"
+ buff->dataStart += decoded;
+ buff->dataCount -= decoded;
+ aio->unread(buff);
+ } else {
+ // Give whole buffer back to aio subsystem
+ aio->queueReadBuffer(buff);
+ }
+ // Check here for read credit
+ if (readCredit.get() != InfiniteCredit) {
+ if (--readCredit == 0) {
+ // Lock and retest credit to make sure we don't race with increasing credit
+ ScopedLock<Mutex> l(creditLock);
+ assert(readCredit.get() >= 0);
+ if (readCredit.get() == 0)
+ return false;
+ }
+ }
+ return true;
+}
+
+void AsynchIOHandler::eof(AsynchIO&) {
+ QPID_LOG(debug, "DISCONNECTED [" << identifier << "]");
+ if (codec) codec->closed();
+ aio->queueWriteClose();
+}
+
+void AsynchIOHandler::closedSocket(AsynchIO&, const Socket& s) {
+ // If we closed with data still to send log a warning
+ if (!aio->writeQueueEmpty()) {
+ QPID_LOG(warning, "CLOSING [" << identifier << "] unsent data (probably due to client disconnect)");
+ }
+ delete &s;
+ aio->queueForDeletion();
+ delete this;
+}
+
+void AsynchIOHandler::disconnect(AsynchIO& a) {
+ // treat the same as eof
+ eof(a);
+}
+
+// Notifications
+void AsynchIOHandler::nobuffs(AsynchIO&) {
+}
+
+void AsynchIOHandler::idle(AsynchIO&){
+ if (isClient && codec == 0) {
+ codec = factory->create(*this, identifier);
+ write(framing::ProtocolInitiation(codec->getVersion()));
+ return;
+ }
+ if (codec == 0) return;
+ if (codec->canEncode()) {
+ // Try and get a queued buffer if not then construct new one
+ AsynchIO::BufferBase* buff = aio->getQueuedBuffer();
+ if (!buff) buff = new Buff;
+ size_t encoded=codec->encode(buff->bytes, buff->byteCount);
+ buff->dataCount = encoded;
+ aio->queueWrite(buff);
+ }
+ if (codec->isClosed())
+ aio->queueWriteClose();
+}
+
+}} // namespace qpid::sys
diff --git a/RC9/qpid/cpp/src/qpid/sys/AsynchIOHandler.h b/RC9/qpid/cpp/src/qpid/sys/AsynchIOHandler.h
new file mode 100644
index 0000000000..fa020fbce4
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/AsynchIOHandler.h
@@ -0,0 +1,79 @@
+#ifndef _sys_AsynchIOHandler_h
+#define _sys_AsynchIOHandler_h
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "OutputControl.h"
+#include "ConnectionCodec.h"
+#include "AtomicValue.h"
+#include "Mutex.h"
+
+namespace qpid {
+
+namespace framing {
+ class ProtocolInitiation;
+}
+
+namespace sys {
+
+class AsynchIO;
+struct AsynchIOBufferBase;
+class Socket;
+
+class AsynchIOHandler : public OutputControl {
+ std::string identifier;
+ AsynchIO* aio;
+ ConnectionCodec::Factory* factory;
+ ConnectionCodec* codec;
+ bool readError;
+ bool isClient;
+ AtomicValue<int32_t> readCredit;
+ static const int32_t InfiniteCredit = -1;
+ Mutex creditLock;
+
+ void write(const framing::ProtocolInitiation&);
+
+ public:
+ AsynchIOHandler(std::string id, ConnectionCodec::Factory* f);
+ ~AsynchIOHandler();
+ void init(AsynchIO* a, int numBuffs);
+
+ void setClient() { isClient = true; }
+
+ // Output side
+ void close();
+ void activateOutput();
+ void giveReadCredit(int32_t credit);
+
+ // Input side
+ bool readbuff(AsynchIO& aio, AsynchIOBufferBase* buff);
+ void eof(AsynchIO& aio);
+ void disconnect(AsynchIO& aio);
+
+ // Notifications
+ void nobuffs(AsynchIO& aio);
+ void idle(AsynchIO& aio);
+ void closedSocket(AsynchIO& aio, const Socket& s);
+};
+
+}} // namespace qpid::sys
+
+#endif // _sys_AsynchIOHandler_h
diff --git a/RC9/qpid/cpp/src/qpid/sys/AtomicCount.h b/RC9/qpid/cpp/src/qpid/sys/AtomicCount.h
new file mode 100644
index 0000000000..d598b49427
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/AtomicCount.h
@@ -0,0 +1,52 @@
+#ifndef _posix_AtomicCount_h
+#define _posix_AtomicCount_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <boost/detail/atomic_count.hpp>
+#include "ScopedIncrement.h"
+
+namespace qpid {
+namespace sys {
+
+/**
+ * Atomic counter.
+ */
+class AtomicCount {
+ public:
+ typedef ::qpid::sys::ScopedDecrement<AtomicCount> ScopedDecrement;
+ typedef ::qpid::sys::ScopedIncrement<AtomicCount> ScopedIncrement;
+
+ AtomicCount(long value = 0) : count(value) {}
+
+ void operator++() { ++count ; }
+
+ long operator--() { return --count; }
+
+ operator long() const { return count; }
+
+ private:
+ boost::detail::atomic_count count;
+};
+
+
+}}
+
+
+#endif // _posix_AtomicCount_h
diff --git a/RC9/qpid/cpp/src/qpid/sys/AtomicValue.h b/RC9/qpid/cpp/src/qpid/sys/AtomicValue.h
new file mode 100644
index 0000000000..6e90eafead
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/AtomicValue.h
@@ -0,0 +1,34 @@
+#ifndef QPID_SYS_ATOMICVALUE_H
+#define QPID_SYS_ATOMICVALUE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#if defined( __GNUC__ ) && __GNUC__ >= 4 && ( defined( __i686__ ) || defined( __x86_64__ ) )
+// Use the Gnu C built-in atomic operations if compiling with gcc on a suitable platform.
+#include "qpid/sys/AtomicValue_gcc.h"
+
+#else
+// Fall-back to mutex locked operations if we don't have atomic ops.
+#include "qpid/sys/AtomicValue_mutex.h"
+#endif
+
+#endif /*!QPID_SYS_ATOMICVALUE_GCC_H*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/AtomicValue_gcc.h b/RC9/qpid/cpp/src/qpid/sys/AtomicValue_gcc.h
new file mode 100644
index 0000000000..d022b07c1d
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/AtomicValue_gcc.h
@@ -0,0 +1,68 @@
+#ifndef QPID_SYS_ATOMICVALUE_GCC_H
+#define QPID_SYS_ATOMICVALUE_GCC_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#if !defined(QPID_SYS_ATOMICVALUE_H)
+#error "This file should only be included via AtomicValue.h."
+#endif
+
+namespace qpid {
+namespace sys {
+
+/**
+ * Atomic value of type T. T must be an integral type of size 1,2,4 or 8 bytes.
+ * All operations are atomic and preform a full memory barrier unless otherwise noted.
+ */
+template <class T>
+class AtomicValue
+{
+ public:
+ AtomicValue(T init=0) : value(init) {}
+
+ // Update and return new value.
+ inline T operator+=(T n) { return __sync_add_and_fetch(&value, n); }
+ inline T operator-=(T n) { return __sync_sub_and_fetch(&value, n); }
+ inline T operator++() { return *this += 1; }
+ inline T operator--() { return *this -= 1; }
+
+ // Update and return old value.
+ inline T fetchAndAdd(T n) { return __sync_fetch_and_add(&value, n); }
+ inline T fetchAndSub(T n) { return __sync_fetch_and_sub(&value, n); }
+ inline T operator++(int) { return fetchAndAdd(1); }
+ inline T operator--(int) { return fetchAndSub(1); }
+
+ /** If current value == testval then set to newval. Returns the old value. */
+ T valueCompareAndSwap(T testval, T newval) { return __sync_val_compare_and_swap(&value, testval, newval); }
+
+ /** If current value == testval then set to newval. Returns true if the swap was performed. */
+ bool boolCompareAndSwap(T testval, T newval) { return __sync_bool_compare_and_swap(&value, testval, newval); }
+
+ T get() const { return const_cast<AtomicValue<T>*>(this)->fetchAndAdd(static_cast<T>(0)); }
+
+ private:
+ T value;
+};
+
+}} // namespace qpid::sys
+
+#endif /*!QPID_SYS_ATOMICVALUE_GCC_H*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/AtomicValue_mutex.h b/RC9/qpid/cpp/src/qpid/sys/AtomicValue_mutex.h
new file mode 100644
index 0000000000..e4d433e7f5
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/AtomicValue_mutex.h
@@ -0,0 +1,83 @@
+#ifndef QPID_SYS_ATOMICVALUE_MUTEX_H
+#define QPID_SYS_ATOMICVALUE_MUTEX_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#if !defined(QPID_SYS_ATOMICVALUE_H)
+#error "This file should only be included via AtomicValue.h."
+#endif
+
+#include "qpid/sys/Mutex.h"
+
+namespace qpid {
+namespace sys {
+
+/**
+ * Atomic value of type T. T must be an integral type of size 1,2,4 or 8 bytes.
+ * All operations are atomic and preform a full memory barrier unless otherwise noted.
+ */
+template <class T>
+class AtomicValue
+{
+ public:
+ AtomicValue(T init=0) : value(init) {}
+
+ // Update and return new value.
+ inline T operator+=(T n) { Lock l(lock); return value += n; }
+ inline T operator-=(T n) { Lock l(lock); return value -= n; }
+ inline T operator++() { return *this += 1; }
+ inline T operator--() { return *this -= 1; }
+
+ // Update and return old value.
+ inline T fetchAndAdd(T n) { Lock l(lock); T old=value; value += n; return old; }
+ inline T fetchAndSub(T n) { Lock l(lock); T old=value; value -= n; return old; }
+ inline T operator++(int) { return fetchAndAdd(1); }
+ inline T operator--(int) { return fetchAndSub(1); }
+
+ AtomicValue& operator=(T newval) { Lock l(lock); value = newval; return *this; }
+
+ /** If current value == testval then set to newval. Returns the old value. */
+ T valueCompareAndSwap(T testval, T newval) {
+ Lock l(lock);
+ T old=value;
+ if (value == testval) value = newval;
+ return old;
+ }
+
+ /** If current value == testval then set to newval. Returns true if the swap was performed. */
+ bool boolCompareAndSwap(T testval, T newval) {
+ Lock l(lock);
+ if (value == testval) { value = newval; return true; }
+ return false;
+ }
+
+ T get() const { Lock l(lock); return value; }
+
+ private:
+ typedef Mutex::ScopedLock Lock;
+ T value;
+ mutable Mutex lock;
+};
+
+}} // namespace qpid::sys
+
+#endif /*!QPID_SYS_ATOMICVALUE_MUTEX_H*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/BlockingQueue.h b/RC9/qpid/cpp/src/qpid/sys/BlockingQueue.h
new file mode 100644
index 0000000000..a05a10d811
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/BlockingQueue.h
@@ -0,0 +1,125 @@
+#ifndef QPID_SYS_BLOCKINGQUEUE_H
+#define QPID_SYS_BLOCKINGQUEUE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Waitable.h"
+
+#include <queue>
+
+namespace qpid {
+namespace sys {
+
+/**
+ * A simple blocking queue template
+ */
+template <class T>
+class BlockingQueue
+{
+ mutable sys::Waitable waitable;
+ std::queue<T> queue;
+
+public:
+ BlockingQueue() {}
+ ~BlockingQueue() { close(); }
+
+ /** Pop from the queue, block up to timeout if empty.
+ *@param result Set to value popped from queue.
+ *@param timeout Defaults to infinite.
+ *@return true if result was set, false if queue empty after timeout.
+ */
+ bool pop(T& result, Duration timeout=TIME_INFINITE) {
+ Mutex::ScopedLock l(waitable);
+ {
+ Waitable::ScopedWait w(waitable);
+ if (timeout == TIME_INFINITE) {
+ while (queue.empty()) waitable.wait();
+ } else {
+ AbsTime deadline(now(),timeout);
+ while (queue.empty() && deadline > now()) waitable.wait(deadline);
+ }
+ }
+ if (queue.empty()) return false;
+ result = queue.front();
+ queue.pop();
+ if (!queue.empty())
+ waitable.notify(); // Notify another waiter.
+ return true;
+ }
+
+ T pop(Duration timeout=TIME_INFINITE) {
+ T result;
+ bool ok = pop(result, timeout);
+ if (!ok)
+ throw Exception("Timed out waiting on a blocking queue");
+ return result;
+ }
+
+ /** Push a value onto the queue.
+ * Note it is not an error to push onto a closed queue.
+ */
+ void push(const T& t) {
+ Mutex::ScopedLock l(waitable);
+ queue.push(t);
+ waitable.notify(); // Notify a waiter.
+ }
+
+ /**
+ * Close the queue.
+ *@ex exception to throw to waiting threads. ClosedException by default.
+ */
+ void close(const ExceptionHolder& ex=ExceptionHolder(new ClosedException()))
+ {
+ Mutex::ScopedLock l(waitable);
+ if (!waitable.hasException()) {
+ waitable.setException(ex);
+ waitable.notifyAll();
+ waitable.waitWaiters(); // Ensure no threads are still waiting.
+ }
+ }
+
+ /** Open a closed queue. */
+ void open() {
+ Mutex::ScopedLock l(waitable);
+ waitable.resetException();
+ }
+
+ bool isClosed() const {
+ Mutex::ScopedLock l(waitable);
+ return waitable.hasException();
+ }
+
+ bool empty() const {
+ Mutex::ScopedLock l(waitable);
+ return queue.empty();
+ }
+ size_t size() const {
+ Mutex::ScopedLock l(waitable);
+ return queue.size();
+ }
+};
+
+}}
+
+
+
+#endif /*!QPID_SYS_BLOCKINGQUEUE_H*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/Condition.h b/RC9/qpid/cpp/src/qpid/sys/Condition.h
new file mode 100644
index 0000000000..fe0e3a1c71
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/Condition.h
@@ -0,0 +1,33 @@
+#ifndef _sys_Condition_h
+#define _sys_Condition_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifdef USE_APR_PLATFORM
+#include "apr/Condition.h"
+#elif defined (_WIN32)
+#include "windows/Condition.h"
+#else
+#include "posix/Condition.h"
+#endif
+
+#endif /*!_sys_Condition_h*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/ConnectionCodec.h b/RC9/qpid/cpp/src/qpid/sys/ConnectionCodec.h
new file mode 100644
index 0000000000..b1b047d2cc
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/ConnectionCodec.h
@@ -0,0 +1,78 @@
+#ifndef QPID_SYS_CONNECTION_CODEC_H
+#define QPID_SYS_CONNECTION_CODEC_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/framing/ProtocolVersion.h"
+
+namespace qpid {
+
+namespace sys {
+
+class InputHandlerFactory;
+class OutputControl;
+
+/**
+ * Interface of coder/decoder for a connection of a specific protocol
+ * version.
+ */
+class ConnectionCodec {
+ public:
+ virtual ~ConnectionCodec() {}
+
+ /** Decode from buffer, return number of bytes decoded.
+ * @return may be less than size if there was incomplete
+ * data at the end of the buffer.
+ */
+ virtual size_t decode(const char* buffer, size_t size) = 0;
+
+
+ /** Encode into buffer, return number of bytes encoded */
+ virtual size_t encode(const char* buffer, size_t size) = 0;
+
+ /** Return true if we have data to encode */
+ virtual bool canEncode() = 0;
+
+ /** Network connection was closed from other end. */
+ virtual void closed() = 0;
+
+ virtual bool isClosed() const = 0;
+
+ virtual framing::ProtocolVersion getVersion() const = 0;
+
+ struct Factory {
+ virtual ~Factory() {}
+
+ /** Return 0 if version unknown */
+ virtual ConnectionCodec* create(
+ framing::ProtocolVersion, OutputControl&, const std::string& id
+ ) = 0;
+
+ /** Return "preferred" codec for outbound connections. */
+ virtual ConnectionCodec* create(
+ OutputControl&, const std::string& id
+ ) = 0;
+ };
+};
+
+}} // namespace qpid::sys
+
+#endif /*!QPID_SYS_CONNECTION_CODEC_H*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/ConnectionInputHandler.h b/RC9/qpid/cpp/src/qpid/sys/ConnectionInputHandler.h
new file mode 100644
index 0000000000..9a5b9f75a5
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/ConnectionInputHandler.h
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _ConnectionInputHandler_
+#define _ConnectionInputHandler_
+
+#include "qpid/framing/InputHandler.h"
+#include "OutputTask.h"
+#include "TimeoutHandler.h"
+
+namespace qpid {
+namespace sys {
+
+ class ConnectionInputHandler :
+ public qpid::framing::InputHandler,
+ public TimeoutHandler, public OutputTask
+ {
+ public:
+
+ virtual void closed() = 0;
+ };
+
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/sys/ConnectionInputHandlerFactory.h b/RC9/qpid/cpp/src/qpid/sys/ConnectionInputHandlerFactory.h
new file mode 100644
index 0000000000..9bb7e13686
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/ConnectionInputHandlerFactory.h
@@ -0,0 +1,54 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _ConnectionInputHandlerFactory_
+#define _ConnectionInputHandlerFactory_
+
+#include <boost/noncopyable.hpp>
+#include <string>
+
+namespace qpid {
+namespace sys {
+
+class ConnectionOutputHandler;
+class ConnectionInputHandler;
+
+/**
+ * Callback interface used by the Acceptor to
+ * create a ConnectionInputHandler for each new connection.
+ */
+class ConnectionInputHandlerFactory : private boost::noncopyable
+{
+ public:
+ /**
+ *@param out handler for connection output.
+ *@param id identify the connection for management purposes.
+ */
+ virtual ConnectionInputHandler* create(ConnectionOutputHandler* out,
+ const std::string& id,
+ bool isClient) = 0;
+
+ virtual ~ConnectionInputHandlerFactory(){}
+};
+
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/sys/ConnectionOutputHandler.h b/RC9/qpid/cpp/src/qpid/sys/ConnectionOutputHandler.h
new file mode 100644
index 0000000000..de0bef3630
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/ConnectionOutputHandler.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _ConnectionOutputHandler_
+#define _ConnectionOutputHandler_
+
+#include "qpid/framing/OutputHandler.h"
+#include "OutputControl.h"
+
+namespace qpid {
+namespace sys {
+
+/**
+ * Provides the output handler associated with a connection.
+ */
+class ConnectionOutputHandler : public virtual qpid::framing::OutputHandler, public OutputControl
+{
+ public:
+ virtual void close() = 0;
+ virtual size_t getBuffered() const { return 0; }
+};
+
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/sys/ConnectionOutputHandlerPtr.h b/RC9/qpid/cpp/src/qpid/sys/ConnectionOutputHandlerPtr.h
new file mode 100644
index 0000000000..df6de89982
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/ConnectionOutputHandlerPtr.h
@@ -0,0 +1,55 @@
+#ifndef QPID_SYS_CONNECTIONOUTPUTHANDLERPTR_H
+#define QPID_SYS_CONNECTIONOUTPUTHANDLERPTR_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "ConnectionOutputHandler.h"
+
+namespace qpid {
+namespace sys {
+
+/**
+ * A ConnectionOutputHandler that delegates to another
+ * ConnectionOutputHandler. Allows the "real" ConnectionOutputHandler
+ * to be changed modified without updating all the pointers/references
+ * using the ConnectionOutputHandlerPtr
+ */
+class ConnectionOutputHandlerPtr : public ConnectionOutputHandler
+{
+ public:
+ ConnectionOutputHandlerPtr(ConnectionOutputHandler* p) : next(p) { assert(next); }
+ void set(ConnectionOutputHandler* p) { next = p; assert(next); }
+ ConnectionOutputHandler* get() { return next; }
+ const ConnectionOutputHandler* get() const { return next; }
+
+ void close() { next->close(); }
+ size_t getBuffered() const { return next->getBuffered(); }
+ void activateOutput() { next->activateOutput(); }
+ void giveReadCredit(int32_t credit) { next->giveReadCredit(credit); }
+ void send(framing::AMQFrame& f) { next->send(f); }
+
+ private:
+ ConnectionOutputHandler* next;
+};
+}} // namespace qpid::sys
+
+#endif /*!QPID_SYS_CONNECTIONOUTPUTHANDLERPTR_H*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/CopyOnWriteArray.h b/RC9/qpid/cpp/src/qpid/sys/CopyOnWriteArray.h
new file mode 100644
index 0000000000..c5bdcc0942
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/CopyOnWriteArray.h
@@ -0,0 +1,126 @@
+#ifndef QPID_SYS_COPYONWRITEARRAY_H
+#define QPID_SYS_COPYONWRITEARRAY_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Mutex.h"
+#include <algorithm>
+#include <vector>
+#include <boost/shared_ptr.hpp>
+
+namespace qpid {
+namespace sys {
+
+/**
+ * An array that copies on adding/removing element allowing lock-free
+ * iteration.
+ */
+template <class T>
+class CopyOnWriteArray
+{
+public:
+ typedef boost::shared_ptr<const std::vector<T> > ConstPtr;
+
+ CopyOnWriteArray() {}
+ CopyOnWriteArray(const CopyOnWriteArray& c) : array(c.array) {}
+
+ void add(T& t)
+ {
+ Mutex::ScopedLock l(lock);
+ ArrayPtr copy(array ? new std::vector<T>(*array) : new std::vector<T>());
+ copy->push_back(t);
+ array = copy;
+ }
+
+ bool remove(T& t)
+ {
+ Mutex::ScopedLock l(lock);
+ if (array && std::find(array->begin(), array->end(), t) != array->end()) {
+ ArrayPtr copy(new std::vector<T>(*array));
+ copy->erase(std::find(copy->begin(), copy->end(), t));
+ array = copy;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ template <class F>
+ bool add_unless(T& t, F f)
+ {
+ Mutex::ScopedLock l(lock);
+ if (array && find_if(array->begin(), array->end(), f) != array->end()) {
+ return false;
+ } else {
+ ArrayPtr copy(array ? new std::vector<T>(*array) : new std::vector<T>());
+ copy->push_back(t);
+ array = copy;
+ return true;
+ }
+ }
+
+ template <class F>
+ bool remove_if(F f)
+ {
+ Mutex::ScopedLock l(lock);
+ if (array && std::find_if(array->begin(), array->end(), f) != array->end()) {
+ ArrayPtr copy(new std::vector<T>(*array));
+ copy->erase(std::remove_if(copy->begin(), copy->end(), f), copy->end());
+ array = copy;
+ return true;
+ }
+ return false;
+ }
+
+ template <class F>
+ F for_each(F f)
+ {
+ ArrayPtr a;
+ {
+ Mutex::ScopedLock l(lock);
+ a = array;
+ }
+ if (!a) return f;
+ return std::for_each(a->begin(), a->end(), f);
+ }
+
+ ConstPtr snapshot()
+ {
+ ConstPtr a;
+ {
+ Mutex::ScopedLock l(lock);
+ a = array;
+ }
+ return a;
+ }
+
+private:
+ typedef boost::shared_ptr< std::vector<T> > ArrayPtr;
+ Mutex lock;
+ ArrayPtr array;
+};
+
+}}
+
+
+
+#endif /*!QPID_SYS_COPYONWRITEARRAY_H*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/DeletionManager.h b/RC9/qpid/cpp/src/qpid/sys/DeletionManager.h
new file mode 100644
index 0000000000..43154eb98e
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/DeletionManager.h
@@ -0,0 +1,138 @@
+#ifndef _sys_DeletionManager_h
+#define _sys_DeletionManager_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <vector>
+#include <algorithm>
+#include <boost/shared_ptr.hpp>
+
+namespace qpid {
+namespace sys {
+
+struct deleter
+{
+ template <typename T>
+ void operator()(T* ptr){ delete ptr;}
+};
+
+/**
+ * DeletionManager keeps track of handles that need to be deleted but may still be
+ * in use by one of the threads concurrently.
+ *
+ * The mode of operation is like this:
+ * - When we want to delete but we might still be using the handle we
+ * * Transfer ownership of the handle to this class
+ * * Mark the handle as (potentially) in use by every thread
+ * - Then subsequently at points where the thread code knows it isn't
+ * using any handles it declares that it is using no handles
+ * - When the last thread declares no use of a handle it automatically
+ * gets deleted by the shared_ptr implementation
+ *
+ * The class only has static members and data and so can only be used once for
+ * any particular handle type
+ */
+template <typename H>
+class DeletionManager
+{
+public:
+ // Mark every thread as using the handle - it will be deleted
+ // below after every thread marks the handle as unused
+ static void markForDeletion(H* handle) {
+ allThreadsStatuses.addHandle(shared_ptr(handle));
+ }
+
+ // Mark this thread is not using any handle -
+ // handles get deleted here when no one else
+ // is using them either
+ static void markAllUnusedInThisThread() {
+ static __thread ThreadStatus* threadStatus = 0;
+
+ // Thread local vars can't be dynamically constructed so we need
+ // to check whether we've made it yet and construct it if not
+ // (no locking necessary for the check as it's thread local!)
+ if (!threadStatus) {
+ threadStatus = new ThreadStatus;
+ allThreadsStatuses.addThreadStatus(threadStatus);
+ }
+
+ ScopedLock<Mutex> l(threadStatus->lock);
+
+ // The actual deletions will happen here when all the shared_ptr
+ // ref counts hit 0 (that is when every thread marks the handle unused)
+ threadStatus->handles.clear();
+ }
+
+private:
+ typedef boost::shared_ptr<H> shared_ptr;
+
+ // In theory we know that we never need more handles than the number of
+ // threads runnning so we could use a fixed size array. However at this point
+ // in the code we don't have easy access to this information.
+ struct ThreadStatus
+ {
+ Mutex lock;
+ std::vector<shared_ptr> handles;
+ };
+
+ class AllThreadsStatuses
+ {
+ Mutex lock;
+ std::vector<ThreadStatus*> statuses;
+
+ struct handleAdder
+ {
+ shared_ptr handle;
+
+ handleAdder(shared_ptr h): handle(h) {}
+
+ void operator()(ThreadStatus* ptr) {
+ ScopedLock<Mutex> l(ptr->lock);
+ ptr->handles.push_back(handle);
+ }
+ };
+
+ public:
+ // Need this to be able to do static initialisation
+ explicit AllThreadsStatuses(int) {}
+
+ ~AllThreadsStatuses() {
+ ScopedLock<Mutex> l(lock);
+ std::for_each(statuses.begin(), statuses.end(), deleter());
+ }
+
+ void addThreadStatus(ThreadStatus* t) {
+ ScopedLock<Mutex> l(lock);
+ statuses.push_back(t);
+ }
+
+ void addHandle(shared_ptr h) {
+ ScopedLock<Mutex> l(lock);
+ std::for_each(statuses.begin(), statuses.end(), handleAdder(h));
+ }
+ };
+
+ static AllThreadsStatuses allThreadsStatuses;
+};
+
+}}
+#endif // _sys_DeletionManager_h
diff --git a/RC9/qpid/cpp/src/qpid/sys/DispatchHandle.cpp b/RC9/qpid/cpp/src/qpid/sys/DispatchHandle.cpp
new file mode 100644
index 0000000000..4722fc0b8b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/DispatchHandle.cpp
@@ -0,0 +1,409 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "DispatchHandle.h"
+
+#include <boost/cast.hpp>
+
+#include <assert.h>
+
+namespace qpid {
+namespace sys {
+
+DispatchHandle::~DispatchHandle() {
+ stopWatch();
+}
+
+void DispatchHandle::startWatch(Poller::shared_ptr poller0) {
+ bool r = readableCallback;
+ bool w = writableCallback;
+
+ ScopedLock<Mutex> lock(stateLock);
+ assert(state == IDLE);
+
+ // If no callbacks set then do nothing (that is what we were asked to do!)
+ // TODO: Maybe this should be an assert instead
+ if (!r && !w) {
+ state = INACTIVE;
+ return;
+ }
+
+ Poller::Direction d = r ?
+ (w ? Poller::INOUT : Poller::INPUT) :
+ Poller::OUTPUT;
+
+ poller = poller0;
+ poller->addFd(*this, d);
+
+ state = r ?
+ (w ? ACTIVE_RW : ACTIVE_R) :
+ ACTIVE_W;
+}
+
+void DispatchHandle::rewatch() {
+ bool r = readableCallback;
+ bool w = writableCallback;
+
+ ScopedLock<Mutex> lock(stateLock);
+ switch(state) {
+ case IDLE:
+ case DELAYED_IDLE:
+ break;
+ case DELAYED_R:
+ case DELAYED_W:
+ case DELAYED_INACTIVE:
+ state = r ?
+ (w ? DELAYED_RW : DELAYED_R) :
+ DELAYED_W;
+ break;
+ case DELAYED_DELETE:
+ break;
+ case INACTIVE:
+ case ACTIVE_R:
+ case ACTIVE_W: {
+ assert(poller);
+ Poller::Direction d = r ?
+ (w ? Poller::INOUT : Poller::INPUT) :
+ Poller::OUTPUT;
+ poller->modFd(*this, d);
+ state = r ?
+ (w ? ACTIVE_RW : ACTIVE_R) :
+ ACTIVE_W;
+ break;
+ }
+ case DELAYED_RW:
+ case ACTIVE_RW:
+ // Don't need to do anything already waiting for readable/writable
+ break;
+ }
+}
+
+void DispatchHandle::rewatchRead() {
+ if (!readableCallback) {
+ return;
+ }
+
+ ScopedLock<Mutex> lock(stateLock);
+ switch(state) {
+ case IDLE:
+ case DELAYED_IDLE:
+ break;
+ case DELAYED_R:
+ case DELAYED_RW:
+ case DELAYED_DELETE:
+ break;
+ case DELAYED_W:
+ state = DELAYED_RW;
+ break;
+ case DELAYED_INACTIVE:
+ state = DELAYED_R;
+ break;
+ case ACTIVE_R:
+ case ACTIVE_RW:
+ // Nothing to do: already waiting for readable
+ break;
+ case INACTIVE:
+ assert(poller);
+ poller->modFd(*this, Poller::INPUT);
+ state = ACTIVE_R;
+ break;
+ case ACTIVE_W:
+ assert(poller);
+ poller->modFd(*this, Poller::INOUT);
+ state = ACTIVE_RW;
+ break;
+ }
+}
+
+void DispatchHandle::rewatchWrite() {
+ if (!writableCallback) {
+ return;
+ }
+
+ ScopedLock<Mutex> lock(stateLock);
+ switch(state) {
+ case IDLE:
+ case DELAYED_IDLE:
+ break;
+ case DELAYED_W:
+ case DELAYED_RW:
+ case DELAYED_DELETE:
+ break;
+ case DELAYED_R:
+ state = DELAYED_RW;
+ break;
+ case DELAYED_INACTIVE:
+ state = DELAYED_W;
+ break;
+ case INACTIVE:
+ assert(poller);
+ poller->modFd(*this, Poller::OUTPUT);
+ state = ACTIVE_W;
+ break;
+ case ACTIVE_R:
+ assert(poller);
+ poller->modFd(*this, Poller::INOUT);
+ state = ACTIVE_RW;
+ break;
+ case ACTIVE_W:
+ case ACTIVE_RW:
+ // Nothing to do: already waiting for writable
+ break;
+ }
+}
+
+void DispatchHandle::unwatchRead() {
+ if (!readableCallback) {
+ return;
+ }
+
+ ScopedLock<Mutex> lock(stateLock);
+ switch(state) {
+ case IDLE:
+ case DELAYED_IDLE:
+ break;
+ case DELAYED_R:
+ state = DELAYED_INACTIVE;
+ break;
+ case DELAYED_RW:
+ state = DELAYED_W;
+ break;
+ case DELAYED_W:
+ case DELAYED_INACTIVE:
+ case DELAYED_DELETE:
+ break;
+ case ACTIVE_R:
+ assert(poller);
+ poller->modFd(*this, Poller::NONE);
+ state = INACTIVE;
+ break;
+ case ACTIVE_RW:
+ assert(poller);
+ poller->modFd(*this, Poller::OUTPUT);
+ state = ACTIVE_W;
+ break;
+ case ACTIVE_W:
+ case INACTIVE:
+ break;
+ }
+}
+
+void DispatchHandle::unwatchWrite() {
+ if (!writableCallback) {
+ return;
+ }
+
+ ScopedLock<Mutex> lock(stateLock);
+ switch(state) {
+ case IDLE:
+ case DELAYED_IDLE:
+ break;
+ case DELAYED_W:
+ state = DELAYED_INACTIVE;
+ break;
+ case DELAYED_RW:
+ state = DELAYED_R;
+ break;
+ case DELAYED_R:
+ case DELAYED_INACTIVE:
+ case DELAYED_DELETE:
+ break;
+ case ACTIVE_W:
+ assert(poller);
+ poller->modFd(*this, Poller::NONE);
+ state = INACTIVE;
+ break;
+ case ACTIVE_RW:
+ assert(poller);
+ poller->modFd(*this, Poller::INPUT);
+ state = ACTIVE_R;
+ break;
+ case ACTIVE_R:
+ case INACTIVE:
+ break;
+ }
+}
+
+void DispatchHandle::unwatch() {
+ ScopedLock<Mutex> lock(stateLock);
+ switch (state) {
+ case IDLE:
+ case DELAYED_IDLE:
+ break;
+ case DELAYED_R:
+ case DELAYED_W:
+ case DELAYED_RW:
+ case DELAYED_INACTIVE:
+ state = DELAYED_INACTIVE;
+ break;
+ case DELAYED_DELETE:
+ break;
+ default:
+ assert(poller);
+ poller->modFd(*this, Poller::NONE);
+ state = INACTIVE;
+ break;
+ }
+}
+
+void DispatchHandle::stopWatch() {
+ ScopedLock<Mutex> lock(stateLock);
+ switch (state) {
+ case IDLE:
+ case DELAYED_IDLE:
+ case DELAYED_DELETE:
+ return;
+ case DELAYED_R:
+ case DELAYED_W:
+ case DELAYED_RW:
+ case DELAYED_INACTIVE:
+ state = DELAYED_IDLE;
+ break;
+ default:
+ state = IDLE;
+ break;
+ }
+ assert(poller);
+ poller->delFd(*this);
+ poller.reset();
+}
+
+// The slightly strange switch structure
+// is to ensure that the lock is released before
+// we do the delete
+void DispatchHandle::doDelete() {
+ // Ensure that we're no longer watching anything
+ stopWatch();
+
+ // If we're in the middle of a callback defer the delete
+ {
+ ScopedLock<Mutex> lock(stateLock);
+ switch (state) {
+ case DELAYED_IDLE:
+ case DELAYED_DELETE:
+ state = DELAYED_DELETE;
+ return;
+ case IDLE:
+ break;
+ default:
+ // Can only get out of stopWatch() in DELAYED_IDLE/DELAYED_DELETE/IDLE states
+ assert(false);
+ }
+ }
+ // If we're not then do it right away
+ delete this;
+}
+
+void DispatchHandle::processEvent(Poller::EventType type) {
+ // Note that we are now doing the callbacks
+ {
+ ScopedLock<Mutex> lock(stateLock);
+
+ // Set up to wait for same events next time unless reset
+ switch(state) {
+ case ACTIVE_R:
+ state = DELAYED_R;
+ break;
+ case ACTIVE_W:
+ state = DELAYED_W;
+ break;
+ case ACTIVE_RW:
+ state = DELAYED_RW;
+ break;
+ // Can only get here in a DELAYED_* state in the rare case
+ // that we're already here for reading and we get activated for
+ // writing and we can write (it might be possible the other way
+ // round too). In this case we're already processing the handle
+ // in a different thread in this function so return right away
+ case DELAYED_R:
+ case DELAYED_W:
+ case DELAYED_RW:
+ case DELAYED_INACTIVE:
+ case DELAYED_IDLE:
+ case DELAYED_DELETE:
+ return;
+ default:
+ assert(false);
+ }
+ }
+
+ // Do callbacks - whilst we are doing the callbacks we are prevented from processing
+ // the same handle until we re-enable it. To avoid rentering the callbacks for a single
+ // handle re-enabling in the callbacks is actually deferred until they are complete.
+ switch (type) {
+ case Poller::READABLE:
+ readableCallback(*this);
+ break;
+ case Poller::WRITABLE:
+ writableCallback(*this);
+ break;
+ case Poller::READ_WRITABLE:
+ readableCallback(*this);
+ writableCallback(*this);
+ break;
+ case Poller::DISCONNECTED:
+ {
+ ScopedLock<Mutex> lock(stateLock);
+ state = DELAYED_INACTIVE;
+ }
+ if (disconnectedCallback) {
+ disconnectedCallback(*this);
+ }
+ break;
+ default:
+ assert(false);
+ }
+
+ // If any of the callbacks re-enabled reading/writing then actually
+ // do it now
+ {
+ ScopedLock<Mutex> lock(stateLock);
+ switch (state) {
+ case DELAYED_R:
+ poller->modFd(*this, Poller::INPUT);
+ state = ACTIVE_R;
+ return;
+ case DELAYED_W:
+ poller->modFd(*this, Poller::OUTPUT);
+ state = ACTIVE_W;
+ return;
+ case DELAYED_RW:
+ poller->modFd(*this, Poller::INOUT);
+ state = ACTIVE_RW;
+ return;
+ case DELAYED_INACTIVE:
+ state = INACTIVE;
+ return;
+ case DELAYED_IDLE:
+ state = IDLE;
+ return;
+ default:
+ // This should be impossible
+ assert(false);
+ return;
+ case DELAYED_DELETE:
+ break;
+ }
+ }
+ delete this;
+}
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/sys/DispatchHandle.h b/RC9/qpid/cpp/src/qpid/sys/DispatchHandle.h
new file mode 100644
index 0000000000..219f2c53d6
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/DispatchHandle.h
@@ -0,0 +1,146 @@
+#ifndef _sys_DispatchHandle_h
+#define _sys_DispatchHandle_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Poller.h"
+#include "Mutex.h"
+
+#include <boost/function.hpp>
+
+
+namespace qpid {
+namespace sys {
+
+class DispatchHandleRef;
+/**
+ * In order to have your own handle (file descriptor on Unix) watched by the poller
+ * you need to:
+ *
+ * - Subclass IOHandle, in the constructor supply an appropriate
+ * IOHandlerPrivate object for the platform.
+ *
+ * - Construct a DispatchHandle passing it your IOHandle and
+ * callback functions for read, write and disconnect events.
+ *
+ * - Ensure the DispatchHandle is not deleted until the poller is no longer using it.
+ * TODO: astitcher document DispatchHandleRef to simplify this.
+ *
+ * When an event occurs on the handle, the poller calls the relevant callback and
+ * stops watching that handle. Your callback can call rewatch() or related functions
+ * to re-enable polling.
+ */
+class DispatchHandle : public PollerHandle {
+ friend class DispatchHandleRef;
+public:
+ typedef boost::function1<void, DispatchHandle&> Callback;
+
+private:
+ Callback readableCallback;
+ Callback writableCallback;
+ Callback disconnectedCallback;
+ Poller::shared_ptr poller;
+ Mutex stateLock;
+ enum {
+ IDLE, INACTIVE, ACTIVE_R, ACTIVE_W, ACTIVE_RW,
+ DELAYED_IDLE, DELAYED_INACTIVE, DELAYED_R, DELAYED_W, DELAYED_RW,
+ DELAYED_DELETE
+ } state;
+
+public:
+ /**
+ * Provide a handle to poll and a set of callbacks. Note
+ * callbacks can be 0, meaning you are not interested in that
+ * event.
+ *
+ *@param h: the handle to watch. The IOHandle encapsulates a
+ * platfrom-specific handle to an IO object (e.g. a file descriptor
+ * on Unix.)
+ *@param rCb Callback called when the handle is readable.
+ *@param wCb Callback called when the handle is writable.
+ *@param dCb Callback called when the handle is disconnected.
+ */
+ DispatchHandle(const IOHandle& h, Callback rCb, Callback wCb, Callback dCb) :
+ PollerHandle(h),
+ readableCallback(rCb),
+ writableCallback(wCb),
+ disconnectedCallback(dCb),
+ state(IDLE)
+ {}
+
+ ~DispatchHandle();
+
+ /** Add this DispatchHandle to the poller to be watched. */
+ void startWatch(Poller::shared_ptr poller);
+
+ /** Resume watchingn for all non-0 callbacks. */
+ void rewatch();
+ /** Resume watchingn for read only. */
+ void rewatchRead();
+
+ /** Resume watchingn for write only. */
+ void rewatchWrite();
+
+ /** Stop watching temporarily. The DispatchHandle remains
+ associated with the poller and can be re-activated using
+ rewatch. */
+ void unwatch();
+ /** Stop watching for read */
+ void unwatchRead();
+ /** Stop watching for write */
+ void unwatchWrite();
+
+ /** Stop watching permanently. Disassociates from the poller. */
+ void stopWatch();
+
+protected:
+ /** Override to get extra processing done when the DispatchHandle is deleted. */
+ void doDelete();
+
+private:
+ void processEvent(Poller::EventType dir);
+};
+
+class DispatchHandleRef {
+ DispatchHandle* ref;
+
+public:
+ typedef boost::function1<void, DispatchHandle&> Callback;
+ DispatchHandleRef(const IOHandle& h, Callback rCb, Callback wCb, Callback dCb) :
+ ref(new DispatchHandle(h, rCb, wCb, dCb))
+ {}
+
+ ~DispatchHandleRef() { ref->doDelete(); }
+
+ void startWatch(Poller::shared_ptr poller) { ref->startWatch(poller); }
+ void rewatch() { ref->rewatch(); }
+ void rewatchRead() { ref->rewatchRead(); }
+ void rewatchWrite() { ref->rewatchWrite(); }
+ void unwatch() { ref->unwatch(); }
+ void unwatchRead() { ref->unwatchRead(); }
+ void unwatchWrite() { ref->unwatchWrite(); }
+ void stopWatch() { ref->stopWatch(); }
+};
+
+}}
+
+#endif // _sys_DispatchHandle_h
diff --git a/RC9/qpid/cpp/src/qpid/sys/Dispatcher.cpp b/RC9/qpid/cpp/src/qpid/sys/Dispatcher.cpp
new file mode 100644
index 0000000000..8d1d1b79f5
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/Dispatcher.cpp
@@ -0,0 +1,59 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Dispatcher.h"
+
+#include <assert.h>
+
+namespace qpid {
+namespace sys {
+
+Dispatcher::Dispatcher(Poller::shared_ptr poller0) :
+ poller(poller0) {
+}
+
+Dispatcher::~Dispatcher() {
+}
+
+void Dispatcher::run() {
+ do {
+ Poller::Event event = poller->wait();
+
+ // If can read/write then dispatch appropriate callbacks
+ if (event.handle) {
+ event.process();
+ } else {
+ // Handle shutdown
+ switch (event.type) {
+ case Poller::SHUTDOWN:
+ goto dispatcher_shutdown;
+ default:
+ // This should be impossible
+ assert(false);
+ }
+ }
+ } while (true);
+
+dispatcher_shutdown:
+ ;
+}
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/sys/Dispatcher.h b/RC9/qpid/cpp/src/qpid/sys/Dispatcher.h
new file mode 100644
index 0000000000..f7c9e8d731
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/Dispatcher.h
@@ -0,0 +1,43 @@
+#ifndef _sys_Dispatcher_h
+#define _sys_Dispatcher_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Poller.h"
+#include "Runnable.h"
+
+namespace qpid {
+namespace sys {
+
+class Dispatcher : public Runnable {
+ const Poller::shared_ptr poller;
+
+public:
+ Dispatcher(Poller::shared_ptr poller);
+ ~Dispatcher();
+
+ void run();
+};
+
+}}
+
+#endif // _sys_Dispatcher_h
diff --git a/RC9/qpid/cpp/src/qpid/sys/ExceptionHolder.h b/RC9/qpid/cpp/src/qpid/sys/ExceptionHolder.h
new file mode 100644
index 0000000000..fecaa73eea
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/ExceptionHolder.h
@@ -0,0 +1,75 @@
+#ifndef QPID_EXCEPTIONHOLDER_H
+#define QPID_EXCEPTIONHOLDER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/memory.h"
+#include <boost/shared_ptr.hpp>
+
+
+namespace qpid {
+namespace sys {
+
+struct Raisable {
+ virtual ~Raisable() {};
+ virtual void raise() const=0;
+ virtual std::string what() const=0;
+};
+
+/**
+ * Holder for exceptions. Allows the thread that notices an error condition to
+ * create an exception and store it to be thrown by another thread.
+ */
+class ExceptionHolder : public Raisable {
+ public:
+ ExceptionHolder() {}
+ // Use default copy & assign.
+
+ /** Take ownership of ex */
+ template <class Ex> ExceptionHolder(Ex* ex) { wrap(ex); }
+ template <class Ex> ExceptionHolder(const boost::shared_ptr<Ex>& ex) { wrap(ex.release()); }
+
+ template <class Ex> ExceptionHolder& operator=(Ex* ex) { wrap(ex); return *this; }
+ template <class Ex> ExceptionHolder& operator=(boost::shared_ptr<Ex> ex) { wrap(ex.release()); return *this; }
+
+ void raise() const { if (wrapper.get()) wrapper->raise() ; }
+ std::string what() const { return wrapper.get() ? wrapper->what() : std::string(); }
+ bool empty() const { return !wrapper.get(); }
+ operator bool() const { return !empty(); }
+ void reset() { wrapper.reset(); }
+
+ private:
+ template <class Ex> struct Wrapper : public Raisable {
+ Wrapper(Ex* ptr) : exception(ptr) {}
+ void raise() const { throw *exception; }
+ std::string what() const { return exception->what(); }
+ boost::shared_ptr<Ex> exception;
+ };
+ template <class Ex> void wrap(Ex* ex) { wrapper.reset(new Wrapper<Ex>(ex)); }
+ boost::shared_ptr<Raisable> wrapper;
+};
+
+
+}} // namespace qpid::sys
+
+
+#endif /*!QPID_EXCEPTIONHOLDER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/FileSysDir.h b/RC9/qpid/cpp/src/qpid/sys/FileSysDir.h
new file mode 100755
index 0000000000..ffe7823f0a
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/FileSysDir.h
@@ -0,0 +1,62 @@
+#ifndef QPID_SYS_FILESYSDIR_H
+#define QPID_SYS_FILESYSDIR_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <string>
+
+namespace qpid {
+namespace sys {
+
+/**
+ * @class FileSysDir
+ *
+ * Represents a filesystem directory accessible from the local host.
+ * This class simply checks existence of, and creates, a directory. It could
+ * be added to later to list contents, etc.
+ */
+class FileSysDir
+{
+ const std::string dirPath;
+
+ public:
+
+ FileSysDir (std::string path) : dirPath(path) {}
+ ~FileSysDir () {}
+
+ /**
+ * Check to see if the directory exists and is a directory. Throws an
+ * exception if there is an error checking existence or if the path
+ * exists but is not a directory.
+ *
+ * @retval true if the path exists and is a directory.
+ * @retval false if the path does not exist.
+ */
+ bool exists (void) const;
+
+ void mkdir(void);
+
+ std::string getPath () { return dirPath; }
+};
+
+}} // namespace qpid::sys
+
+#endif /*!QPID_SYS_FILESYSDIR_H*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/Fork.h b/RC9/qpid/cpp/src/qpid/sys/Fork.h
new file mode 100644
index 0000000000..4ec061f7bc
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/Fork.h
@@ -0,0 +1,24 @@
+#ifndef QPID_SYS_FORK_H
+#define QPID_SYS_FORK_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "posix/Fork.h"
+
+#endif /*!QPID_SYS_FORK_H*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/IOHandle.h b/RC9/qpid/cpp/src/qpid/sys/IOHandle.h
new file mode 100644
index 0000000000..0bf2abbafa
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/IOHandle.h
@@ -0,0 +1,59 @@
+#ifndef _sys_IOHandle_h
+#define _sys_IOHandle_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+namespace qpid {
+namespace sys {
+
+/**
+ * This is a class intended to abstract the Unix concept of file descriptor
+ * or the Windows concept of HANDLE
+ */
+// Windows-related classes
+class AsynchAcceptorPrivate;
+class AsynchAcceptResult;
+namespace windows {
+ class AsynchIO;
+}
+
+// General classes
+class PollerHandle;
+class IOHandlePrivate;
+class IOHandle {
+
+ friend class AsynchAcceptorPrivate;
+ friend class AsynchAcceptResult;
+ friend class windows::AsynchIO;
+
+ friend class PollerHandle;
+
+protected:
+ IOHandlePrivate* const impl;
+
+ IOHandle(IOHandlePrivate*);
+ virtual ~IOHandle();
+};
+
+}}
+
+#endif // _sys_IOHandle_h
diff --git a/RC9/qpid/cpp/src/qpid/sys/IntegerTypes.h b/RC9/qpid/cpp/src/qpid/sys/IntegerTypes.h
new file mode 100755
index 0000000000..89635f033e
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/IntegerTypes.h
@@ -0,0 +1,31 @@
+#ifndef QPID_SYS_INTEGERTYPES_H
+#define QPID_SYS_INTEGERTYPES_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#if (defined(_WINDOWS) || defined (WIN32)) && defined(_MSC_VER)
+#include "qpid/sys/windows/IntegerTypes.h"
+#endif
+#if !defined _WINDOWS && !defined WIN32
+#include "qpid/sys/posix/IntegerTypes.h"
+#endif
+
+#endif /*!QPID_SYS_INTEGERTYPES_H*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/LockFile.h b/RC9/qpid/cpp/src/qpid/sys/LockFile.h
new file mode 100644
index 0000000000..2ff8c2f6d4
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/LockFile.h
@@ -0,0 +1,80 @@
+#ifndef _sys_LockFile_h
+#define _sys_LockFile_h
+
+/*
+ *
+ * Copyright (c) 2008 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <string>
+
+#include "IntegerTypes.h"
+
+namespace qpid {
+namespace sys {
+
+class LockFilePrivate;
+
+/**
+ * @class LockFile
+ *
+ * LockFile represents a locked file suitable for a coarse-grain system
+ * lock. For example, the broker uses this to ensure that only one broker
+ * runs. A common usage idiom is to store the current "owner" process ID
+ * in the lock file - if the lock file exists, but the stored process ID
+ * doesn't, the old owner has probably died without cleaning up the lock
+ * file.
+ */
+class LockFile : private boost::noncopyable
+{
+ boost::shared_ptr<LockFilePrivate> impl;
+
+ std::string path;
+ bool created;
+
+public:
+ LockFile(const std::string& path_, bool create);
+ ~LockFile();
+
+ /**
+ * Read the process ID from the lock file. This method assumes that
+ * if there is a process ID in the file, it was written there by
+ * writePid(); thus, it's at the start of the file.
+ *
+ * Throws an exception if there is an error reading the file.
+ *
+ * @returns The stored process ID. No validity check is done on it.
+ */
+ pid_t readPid(void) const;
+
+ /**
+ * Write the current process's ID to the lock file. It's written at
+ * the start of the file and will overwrite any other content that
+ * may be in the file.
+ *
+ * Throws an exception if the write fails.
+ */
+ void writePid(void);
+};
+
+}} /* namespace qpid::sys */
+
+#endif /*!_sys_LockFile_h*/
+
+
+
diff --git a/RC9/qpid/cpp/src/qpid/sys/LockPtr.h b/RC9/qpid/cpp/src/qpid/sys/LockPtr.h
new file mode 100644
index 0000000000..738a864317
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/LockPtr.h
@@ -0,0 +1,89 @@
+#ifndef QPID_SYS_LOCKPTR_H
+#define QPID_SYS_LOCKPTR_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Mutex.h"
+#include <boost/noncopyable.hpp>
+
+namespace qpid {
+namespace sys {
+
+class Mutex;
+
+/**
+ * LockPtr is a smart pointer to T. It is constructed from a volatile
+ * T* and a Lock (by default a Mutex). It const_casts away the
+ * volatile qualifier and locks the Lock for the duration of its
+ *
+ * Used in conjuntion with the "volatile" keyword to get the compiler
+ * to help enforce correct concurrent use of mutli-threaded objects.
+ * See ochttp://www.ddj.com/cpp/184403766 for a detailed discussion.
+ *
+ * To summarize the convention:
+ * - Declare thread-safe member functions as volatile.
+ * - Declare instances of the class that may be called concurrently as volatile.
+ * - Use LockPtr to cast away the volatile qualifier while taking a lock.
+ *
+ * This means that code calling on a concurrently-used object
+ * (declared volatile) can only call thread-safe (volatile) member
+ * functions. Code that needs to use thread-unsafe members must use a
+ * LockPtr, thereby acquiring the lock and making it safe to do so.
+ *
+ * A good type-safe pattern is the internally-locked object:
+ * - It has it's own private lock member.
+ * - All public functions are thread safe and declared volatile.
+ * - Any thread-unsafe, non-volatile functions are private.
+ * - Only member function implementations use LockPtr to access private functions.
+ *
+ * This encapsulates all the locking logic inside the class.
+ *
+ * One nice feature of this convention is the common case where you
+ * need a public, locked version of some function foo() and also a
+ * private unlocked version to avoid recursive locks. They can be declared as
+ * volatile and non-volatile overloads of the same function:
+ *
+ * // public
+ * void Thing::foo() volatile { LockPtr<Thing>(this, myLock)->foo(); }
+ * // private
+ * void Thing::foo() { ... do stuff ...}
+ */
+
+template <class T, class Lock> class LockPtr : public boost::noncopyable {
+ public:
+ LockPtr(volatile T* p, Lock& l) : ptr(const_cast<T*>(p)), lock(l) { lock.lock(); }
+ LockPtr(volatile T* p, volatile Lock& l) : ptr(const_cast<T*>(p)), lock(const_cast<Lock&>(l)) { lock.lock(); }
+ ~LockPtr() { lock.unlock(); }
+
+ T& operator*() { return *ptr; }
+ T* operator->() { return ptr; }
+
+ private:
+ T* ptr;
+ Lock& lock;
+};
+
+
+}} // namespace qpid::sys
+
+
+#endif /*!QPID_SYS_LOCKPTR_H*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/Monitor.h b/RC9/qpid/cpp/src/qpid/sys/Monitor.h
new file mode 100644
index 0000000000..2dd405efaf
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/Monitor.h
@@ -0,0 +1,49 @@
+#ifndef _sys_Monitor_h
+#define _sys_Monitor_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Condition.h"
+
+namespace qpid {
+namespace sys {
+
+/**
+ * A monitor is a condition variable and a mutex
+ */
+class Monitor : public Mutex, public Condition {
+ public:
+ inline void wait();
+ inline bool wait(const AbsTime& absoluteTime);
+};
+
+
+void Monitor::wait() {
+ Condition::wait(*this);
+}
+
+bool Monitor::wait(const AbsTime& absoluteTime) {
+ return Condition::wait(*this, absoluteTime);
+}
+
+}}
+#endif /*!_sys_Monitor_h*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/Mutex.h b/RC9/qpid/cpp/src/qpid/sys/Mutex.h
new file mode 100644
index 0000000000..00bf392604
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/Mutex.h
@@ -0,0 +1,91 @@
+#ifndef _sys_Mutex_h
+#define _sys_Mutex_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace qpid {
+namespace sys {
+
+/**
+ * Scoped lock template: calls lock() in ctor, unlock() in dtor.
+ * L can be any class with lock() and unlock() functions.
+ */
+template <class L>
+class ScopedLock
+{
+ public:
+ ScopedLock(L& l) : mutex(l) { l.lock(); }
+ ~ScopedLock() { mutex.unlock(); }
+ private:
+ L& mutex;
+};
+
+template <class L>
+class ScopedUnlock
+{
+ public:
+ ScopedUnlock(L& l) : mutex(l) { l.unlock(); }
+ ~ScopedUnlock() { mutex.lock(); }
+ private:
+ L& mutex;
+};
+
+template <class L>
+class ScopedRlock
+{
+ public:
+ ScopedRlock(L& l) : mutex(l) { l.rlock(); }
+ ~ScopedRlock() { mutex.unlock(); }
+ private:
+ L& mutex;
+};
+
+template <class L>
+class ScopedWlock
+{
+ public:
+ ScopedWlock(L& l) : mutex(l) { l.wlock(); }
+ ~ScopedWlock() { mutex.unlock(); }
+ private:
+ L& mutex;
+};
+
+template <class L>
+class ConditionalScopedLock
+{
+ public:
+ ConditionalScopedLock(L& l) : mutex(l) { acquired = l.trylock(); }
+ ~ConditionalScopedLock() { if (acquired) mutex.unlock(); }
+ bool lockAcquired() { return acquired; }
+ private:
+ L& mutex;
+ bool acquired;
+};
+
+}}
+
+#ifdef USE_APR_PLATFORM
+#include "apr/Mutex.h"
+#elif defined (_WIN32)
+#include "windows/Mutex.h"
+#else
+#include "posix/Mutex.h"
+#endif
+
+#endif /*!_sys_Mutex_h*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/OutputControl.h b/RC9/qpid/cpp/src/qpid/sys/OutputControl.h
new file mode 100644
index 0000000000..e9e6c57a9b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/OutputControl.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "IntegerTypes.h"
+
+#ifndef _OutputControl_
+#define _OutputControl_
+
+namespace qpid {
+namespace sys {
+
+ class OutputControl
+ {
+ public:
+ virtual ~OutputControl() {}
+ virtual void activateOutput() = 0;
+ virtual void giveReadCredit(int32_t credit) = 0;
+ };
+
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/sys/OutputTask.h b/RC9/qpid/cpp/src/qpid/sys/OutputTask.h
new file mode 100644
index 0000000000..005ae7dbc4
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/OutputTask.h
@@ -0,0 +1,48 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _OutputTask_
+#define _OutputTask_
+
+namespace qpid {
+namespace sys {
+
+ class OutputTask
+ {
+ public:
+ virtual ~OutputTask() {}
+ /** Generate some output.
+ *@return true if output was generated, false if there is no work to do.
+ */
+ virtual bool doOutput() = 0;
+
+ /** Check if there may be work to do, but don't do it.
+ * @return True if there may be work to do, false if there is none.
+ * Can to return a false positive, to allow implementations to do a
+ * faster check than doOutput(). Must never return a false negative.
+ */
+ virtual bool hasOutput() = 0;
+ };
+
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/sys/PollableCondition.h b/RC9/qpid/cpp/src/qpid/sys/PollableCondition.h
new file mode 100644
index 0000000000..56d38f90da
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/PollableCondition.h
@@ -0,0 +1,28 @@
+#ifndef QPID_SYS_POLLABLECONDITION_H
+#define QPID_SYS_POLLABLECONDITION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+// Currently only has a posix implementation, add #ifdefs for other platforms as needed.
+#include "posix/PollableCondition.h"
+
+#endif /*!QPID_SYS_POLLABLECONDITION_H*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/PollableQueue.h b/RC9/qpid/cpp/src/qpid/sys/PollableQueue.h
new file mode 100644
index 0000000000..7f11cc35a9
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/PollableQueue.h
@@ -0,0 +1,152 @@
+#ifndef QPID_SYS_POLLABLEQUEUE_H
+#define QPID_SYS_POLLABLEQUEUE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/PollableCondition.h"
+#include "qpid/sys/Dispatcher.h"
+#include "qpid/sys/DispatchHandle.h"
+#include "qpid/sys/Monitor.h"
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+#include <algorithm>
+#include <deque>
+
+namespace qpid {
+namespace sys {
+
+class Poller;
+
+/**
+ * A queue that can be polled by sys::Poller. Any thread can push to
+ * the queue, on wakeup the poller thread processes all items on the
+ * queue by passing them to a callback in a batch.
+ */
+template <class T>
+class PollableQueue {
+ public:
+ typedef std::deque<T> Queue;
+
+ /**
+ * Callback to process a batch of items from the queue.
+ * @param values to process, any items remaining after call are put back on the queue.
+ */
+ typedef boost::function<void (Queue& values)> Callback;
+
+ /** When the queue is selected by the poller, values are passed to callback cb. */
+ PollableQueue(const Callback& cb, const boost::shared_ptr<sys::Poller>& poller);
+
+ ~PollableQueue();
+
+ /** Push a value onto the queue. Thread safe */
+ void push(const T& t);
+
+ /** Start polling. */
+ void start();
+
+ /** Stop polling and wait for the current callback, if any, to complete. */
+ void stop();
+
+ /** Are we currently stopped?*/
+ bool isStopped() const { ScopedLock l(lock); return stopped; }
+
+ size_t size() { ScopedLock l(lock); return queue.size(); }
+ bool empty() { ScopedLock l(lock); return queue.empty(); }
+
+ private:
+ typedef sys::Monitor::ScopedLock ScopedLock;
+ typedef sys::Monitor::ScopedUnlock ScopedUnlock;
+
+ void dispatch(sys::DispatchHandle&);
+
+ mutable sys::Monitor lock;
+ Callback callback;
+ boost::shared_ptr<sys::Poller> poller;
+ PollableCondition condition;
+ DispatchHandle handle;
+ Queue queue, batch;
+ Thread dispatcher;
+ bool stopped;
+};
+
+template <class T> PollableQueue<T>::PollableQueue(
+ const Callback& cb, const boost::shared_ptr<sys::Poller>& p)
+ : callback(cb), poller(p),
+ handle(condition, boost::bind(&PollableQueue<T>::dispatch, this, _1), 0, 0), stopped(true)
+{
+ handle.startWatch(poller);
+ handle.unwatch();
+}
+
+template <class T> void PollableQueue<T>::start() {
+ ScopedLock l(lock);
+ if (!stopped) return;
+ stopped = false;
+ if (!queue.empty()) condition.set();
+ handle.rewatch();
+}
+
+template <class T> PollableQueue<T>::~PollableQueue() {
+ handle.stopWatch();
+}
+
+template <class T> void PollableQueue<T>::push(const T& t) {
+ ScopedLock l(lock);
+ if (queue.empty()) condition.set();
+ queue.push_back(t);
+}
+
+template <class T> void PollableQueue<T>::dispatch(sys::DispatchHandle& h) {
+ ScopedLock l(lock);
+ assert(dispatcher.id() == 0);
+ dispatcher = Thread::current();
+ while (!stopped && !queue.empty()) {
+ assert(batch.empty());
+ batch.swap(queue);
+ {
+ ScopedUnlock u(lock); // Allow concurrent push to queue.
+ callback(batch);
+ }
+ if (!batch.empty()) {
+ queue.insert(queue.begin(), batch.begin(), batch.end()); // put back unprocessed items.
+ batch.clear();
+ }
+ }
+ dispatcher = Thread();
+ if (queue.empty()) condition.clear();
+ if (stopped) lock.notifyAll();
+ else h.rewatch();
+}
+
+template <class T> void PollableQueue<T>::stop() {
+ ScopedLock l(lock);
+ if (stopped) return;
+ handle.unwatch();
+ stopped = true;
+ // Avoid deadlock if stop is called from the dispatch thread
+ while (dispatcher.id() && dispatcher.id() != Thread::current().id())
+ lock.wait();
+}
+
+}} // namespace qpid::sys
+
+#endif /*!QPID_SYS_POLLABLEQUEUE_H*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/Poller.h b/RC9/qpid/cpp/src/qpid/sys/Poller.h
new file mode 100644
index 0000000000..6b7f4d818e
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/Poller.h
@@ -0,0 +1,109 @@
+#ifndef _sys_Poller_h
+#define _sys_Poller_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Time.h"
+
+#include <boost/shared_ptr.hpp>
+
+namespace qpid {
+namespace sys {
+
+/**
+ * Poller: abstract class to encapsulate a file descriptor poll to be used
+ * by a reactor.
+ *
+ * @see DispatchHandler for more details of normal use.
+ */
+class PollerHandle;
+class PollerPrivate;
+class Poller {
+ PollerPrivate* const impl;
+
+public:
+ typedef boost::shared_ptr<Poller> shared_ptr;
+
+ enum Direction {
+ NONE = 0,
+ INPUT,
+ OUTPUT,
+ INOUT
+ };
+
+ enum EventType {
+ INVALID = 0,
+ READABLE,
+ WRITABLE,
+ READ_WRITABLE,
+ DISCONNECTED,
+ SHUTDOWN,
+ TIMEOUT
+ };
+
+ struct Event {
+ PollerHandle* handle;
+ EventType type;
+
+ Event(PollerHandle* handle0, EventType type0) :
+ handle(handle0),
+ type(type0) {
+ }
+
+ void process();
+ };
+
+ Poller();
+ ~Poller();
+ /** Note: this function is async-signal safe */
+ void shutdown();
+
+ void addFd(PollerHandle& handle, Direction dir);
+ void delFd(PollerHandle& handle);
+ void modFd(PollerHandle& handle, Direction dir);
+ void rearmFd(PollerHandle& handle);
+ Event wait(Duration timeout = TIME_INFINITE);
+};
+
+/**
+ * Handle class to use for polling
+ */
+class IOHandle;
+class PollerHandlePrivate;
+class PollerHandle {
+ friend class Poller;
+ friend struct Poller::Event;
+
+ PollerHandlePrivate* const impl;
+ virtual void processEvent(Poller::EventType) {};
+
+public:
+ PollerHandle(const IOHandle& h);
+ virtual ~PollerHandle();
+};
+
+inline void Poller::Event::process() {
+ handle->processEvent(type);
+}
+
+}}
+#endif // _sys_Poller_h
diff --git a/RC9/qpid/cpp/src/qpid/sys/ProtocolFactory.h b/RC9/qpid/cpp/src/qpid/sys/ProtocolFactory.h
new file mode 100644
index 0000000000..56ab404d82
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/ProtocolFactory.h
@@ -0,0 +1,58 @@
+#ifndef _sys_ProtocolFactory_h
+#define _sys_ProtocolFactory_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/IntegerTypes.h"
+#include "qpid/SharedObject.h"
+#include "ConnectionCodec.h"
+#include <boost/function.hpp>
+
+namespace qpid {
+namespace sys {
+
+class Poller;
+
+class ProtocolFactory : public qpid::SharedObject<ProtocolFactory>
+{
+ public:
+ typedef boost::function2<void, int, std::string> ConnectFailedCallback;
+
+ virtual ~ProtocolFactory() = 0;
+ virtual uint16_t getPort() const = 0;
+ virtual std::string getHost() const = 0;
+ virtual void accept(boost::shared_ptr<Poller>, ConnectionCodec::Factory*) = 0;
+ virtual void connect(
+ boost::shared_ptr<Poller>,
+ const std::string& host, int16_t port,
+ ConnectionCodec::Factory* codec,
+ ConnectFailedCallback failed) = 0;
+ virtual bool supports(const std::string& /*capability*/) { return false; }
+};
+
+inline ProtocolFactory::~ProtocolFactory() {}
+
+}}
+
+
+
+#endif //!_sys_ProtocolFactory_h
diff --git a/RC9/qpid/cpp/src/qpid/sys/RdmaIOPlugin.cpp b/RC9/qpid/cpp/src/qpid/sys/RdmaIOPlugin.cpp
new file mode 100644
index 0000000000..8afe8ba5ef
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/RdmaIOPlugin.cpp
@@ -0,0 +1,356 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "ProtocolFactory.h"
+
+#include "qpid/Plugin.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/framing/AMQP_HighestVersion.h"
+#include "qpid/log/Statement.h"
+#include "qpid/sys/rdma/RdmaIO.h"
+#include "qpid/sys/OutputControl.h"
+
+#include <boost/bind.hpp>
+#include <memory>
+
+#include <netdb.h>
+
+using std::auto_ptr;
+using std::string;
+using std::stringstream;
+
+namespace qpid {
+namespace sys {
+
+class RdmaIOHandler : public OutputControl {
+ Rdma::Connection::intrusive_ptr connection;
+ std::string identifier;
+ Rdma::AsynchIO* aio;
+ ConnectionCodec::Factory* factory;
+ ConnectionCodec* codec;
+ bool readError;
+
+ void write(const framing::ProtocolInitiation&);
+
+ public:
+ RdmaIOHandler(Rdma::Connection::intrusive_ptr& c, ConnectionCodec::Factory* f);
+ ~RdmaIOHandler();
+ void init(Rdma::AsynchIO* a);
+ void start(Poller::shared_ptr poller) {aio->start(poller);}
+
+ // Output side
+ void close();
+ void activateOutput();
+ void giveReadCredit(int32_t credit);
+ void initProtocolOut();
+
+ // Input side
+ void readbuff(Rdma::AsynchIO& aio, Rdma::Buffer* buff);
+ void initProtocolIn(Rdma::Buffer* buff);
+
+ // Notifications
+ void full(Rdma::AsynchIO& aio);
+ void idle(Rdma::AsynchIO& aio);
+ void error(Rdma::AsynchIO& aio);
+};
+
+RdmaIOHandler::RdmaIOHandler(Rdma::Connection::intrusive_ptr& c, qpid::sys::ConnectionCodec::Factory* f) :
+ connection(c),
+ identifier(c->getPeerName()),
+ factory(f),
+ codec(0),
+ readError(false)
+{
+}
+
+void RdmaIOHandler::init(Rdma::AsynchIO* a) {
+ aio = a;
+}
+
+RdmaIOHandler::~RdmaIOHandler() {
+ if (codec)
+ codec->closed();
+ delete codec;
+
+ aio->deferDelete();
+}
+
+void RdmaIOHandler::write(const framing::ProtocolInitiation& data)
+{
+ QPID_LOG(debug, "Rdma: SENT [" << identifier << "] INIT(" << data << ")");
+ Rdma::Buffer* buff = aio->getBuffer();
+ framing::Buffer out(buff->bytes, buff->byteCount);
+ data.encode(out);
+ buff->dataCount = data.encodedSize();
+ aio->queueWrite(buff);
+}
+
+void RdmaIOHandler::close() {
+ aio->queueWriteClose();
+}
+
+void RdmaIOHandler::activateOutput() {
+ aio->notifyPendingWrite();
+}
+
+void RdmaIOHandler::idle(Rdma::AsynchIO&) {
+ // TODO: Shouldn't need this test as idle() should only ever be called when
+ // the connection is writable anyway
+ if ( !(aio->writable() && aio->bufferAvailable()) ) {
+ return;
+ }
+ if (codec == 0) return;
+ if (codec->canEncode()) {
+ Rdma::Buffer* buff = aio->getBuffer();
+ size_t encoded=codec->encode(buff->bytes, buff->byteCount);
+ buff->dataCount = encoded;
+ aio->queueWrite(buff);
+ }
+ if (codec->isClosed())
+ aio->queueWriteClose();
+}
+
+void RdmaIOHandler::initProtocolOut() {
+ // We mustn't have already started the conversation
+ // but we must be able to send
+ assert( codec == 0 );
+ assert( aio->writable() && aio->bufferAvailable() );
+ codec = factory->create(*this, identifier);
+ write(framing::ProtocolInitiation(codec->getVersion()));
+}
+
+void RdmaIOHandler::error(Rdma::AsynchIO&) {
+ close();
+}
+
+void RdmaIOHandler::full(Rdma::AsynchIO&) {
+ QPID_LOG(debug, "Rdma: buffer full [" << identifier << "]");
+}
+
+// TODO: Dummy implementation of read throttling
+void RdmaIOHandler::giveReadCredit(int32_t) {
+}
+
+// The logic here is subtly different from TCP as RDMA is message oriented
+// so we define that an RDMA message is a frame - in this case there is no putting back
+// of any message remainder - there shouldn't be any. And what we read here can't be
+// smaller than a frame
+void RdmaIOHandler::readbuff(Rdma::AsynchIO&, Rdma::Buffer* buff) {
+ if (readError) {
+ return;
+ }
+ size_t decoded = 0;
+ try {
+ if (codec) {
+ decoded = codec->decode(buff->bytes+buff->dataStart, buff->dataCount);
+ }else{
+ // Need to start protocol processing
+ initProtocolIn(buff);
+ }
+ }catch(const std::exception& e){
+ QPID_LOG(error, e.what());
+ readError = true;
+ aio->queueWriteClose();
+ }
+}
+
+void RdmaIOHandler::initProtocolIn(Rdma::Buffer* buff) {
+ framing::Buffer in(buff->bytes+buff->dataStart, buff->dataCount);
+ framing::ProtocolInitiation protocolInit;
+ size_t decoded = 0;
+ if (protocolInit.decode(in)) {
+ decoded = in.getPosition();
+ QPID_LOG(debug, "Rdma: RECV [" << identifier << "] INIT(" << protocolInit << ")");
+
+ codec = factory->create(protocolInit.getVersion(), *this, identifier);
+
+ // If we failed to create the codec then we don't understand the offered protocol version
+ if (!codec) {
+ // send valid version header & close connection.
+ write(framing::ProtocolInitiation(framing::highestProtocolVersion));
+ readError = true;
+ aio->queueWriteClose();
+ }
+ }
+}
+
+class RdmaIOProtocolFactory : public ProtocolFactory {
+ auto_ptr<Rdma::Listener> listener;
+ const uint16_t listeningPort;
+
+ public:
+ RdmaIOProtocolFactory(int16_t port, int backlog);
+ void accept(Poller::shared_ptr, ConnectionCodec::Factory*);
+ void connect(Poller::shared_ptr, const string& host, int16_t port, ConnectionCodec::Factory*, ConnectFailedCallback);
+
+ uint16_t getPort() const;
+ string getHost() const;
+
+ private:
+ bool request(Rdma::Connection::intrusive_ptr&, const Rdma::ConnectionParams&, ConnectionCodec::Factory*);
+ void established(Poller::shared_ptr, Rdma::Connection::intrusive_ptr&);
+ void connected(Poller::shared_ptr, Rdma::Connection::intrusive_ptr&, const Rdma::ConnectionParams&, ConnectionCodec::Factory*);
+ void connectionError(Rdma::Connection::intrusive_ptr&, Rdma::ErrorType);
+ void disconnected(Rdma::Connection::intrusive_ptr&);
+ void rejected(Rdma::Connection::intrusive_ptr&, const Rdma::ConnectionParams&, ConnectFailedCallback);
+};
+
+// Static instance to initialise plugin
+static class RdmaIOPlugin : public Plugin {
+ void earlyInitialize(Target&) {
+ }
+
+ void initialize(Target& target) {
+ // Check whether we actually have any rdma devices
+ if ( Rdma::deviceCount() == 0 ) {
+ QPID_LOG(info, "Rdma: Disabled: no rdma devices found");
+ return;
+ }
+
+ broker::Broker* broker = dynamic_cast<broker::Broker*>(&target);
+ // Only provide to a Broker
+ if (broker) {
+ const broker::Broker::Options& opts = broker->getOptions();
+ ProtocolFactory::shared_ptr protocol(new RdmaIOProtocolFactory(opts.port, opts.connectionBacklog));
+ QPID_LOG(notice, "Rdma: Listening on RDMA port " << protocol->getPort());
+ broker->registerProtocolFactory("rdma", protocol);
+ }
+ }
+} rdmaPlugin;
+
+RdmaIOProtocolFactory::RdmaIOProtocolFactory(int16_t port, int /*backlog*/) :
+ listeningPort(port)
+{}
+
+void RdmaIOProtocolFactory::established(Poller::shared_ptr poller, Rdma::Connection::intrusive_ptr& ci) {
+ RdmaIOHandler* async = ci->getContext<RdmaIOHandler>();
+ async->start(poller);
+}
+
+bool RdmaIOProtocolFactory::request(Rdma::Connection::intrusive_ptr& ci, const Rdma::ConnectionParams& cp,
+ ConnectionCodec::Factory* f) {
+ try {
+ RdmaIOHandler* async = new RdmaIOHandler(ci, f);
+ Rdma::AsynchIO* aio =
+ new Rdma::AsynchIO(ci->getQueuePair(),
+ cp.maxRecvBufferSize, cp.initialXmitCredit, Rdma::DEFAULT_WR_ENTRIES,
+ boost::bind(&RdmaIOHandler::readbuff, async, _1, _2),
+ boost::bind(&RdmaIOHandler::idle, async, _1),
+ 0, // boost::bind(&RdmaIOHandler::full, async, _1),
+ boost::bind(&RdmaIOHandler::error, async, _1));
+ async->init(aio);
+
+ // Record aio so we can get it back from a connection
+ ci->addContext(async);
+ return true;
+ } catch (const Rdma::Exception& e) {
+ QPID_LOG(error, "Rdma: Cannot accept new connection (Rdma exception): " << e.what());
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Rdma: Cannot accept new connection (unknown exception): " << e.what());
+ }
+
+ // If we get here we caught an exception so reject connection
+ return false;
+}
+
+void RdmaIOProtocolFactory::connectionError(Rdma::Connection::intrusive_ptr&, Rdma::ErrorType) {
+}
+
+void RdmaIOProtocolFactory::disconnected(Rdma::Connection::intrusive_ptr& ci) {
+ // If we've got a connection already tear it down, otherwise ignore
+ RdmaIOHandler* async = ci->getContext<RdmaIOHandler>();
+ if (async) {
+ async->close();
+ }
+ delete async;
+}
+
+uint16_t RdmaIOProtocolFactory::getPort() const {
+ return listeningPort; // Immutable no need for lock.
+}
+
+string RdmaIOProtocolFactory::getHost() const {
+ //return listener.getSockname();
+ return "";
+}
+
+void RdmaIOProtocolFactory::accept(Poller::shared_ptr poller, ConnectionCodec::Factory* fact) {
+ ::sockaddr_in sin;
+
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(listeningPort);
+ sin.sin_addr.s_addr = INADDR_ANY;
+
+ listener.reset(
+ new Rdma::Listener((const sockaddr&)(sin),
+ Rdma::ConnectionParams(65536, Rdma::DEFAULT_WR_ENTRIES),
+ boost::bind(&RdmaIOProtocolFactory::established, this, poller, _1),
+ boost::bind(&RdmaIOProtocolFactory::connectionError, this, _1, _2),
+ boost::bind(&RdmaIOProtocolFactory::disconnected, this, _1),
+ boost::bind(&RdmaIOProtocolFactory::request, this, _1, _2, fact)));
+
+ listener->start(poller);
+}
+
+// Only used for outgoing connections (in federation)
+void RdmaIOProtocolFactory::rejected(Rdma::Connection::intrusive_ptr&, const Rdma::ConnectionParams&, ConnectFailedCallback failed) {
+ failed(-1, "Connection rejected");
+}
+
+// Do the same as connection request and established but mark a client too
+void RdmaIOProtocolFactory::connected(Poller::shared_ptr poller, Rdma::Connection::intrusive_ptr& ci, const Rdma::ConnectionParams& cp,
+ ConnectionCodec::Factory* f) {
+ (void) request(ci, cp, f);
+ established(poller, ci);
+ RdmaIOHandler* async = ci->getContext<RdmaIOHandler>();
+ async->initProtocolOut();
+}
+
+void RdmaIOProtocolFactory::connect(
+ Poller::shared_ptr poller,
+ const std::string& host, int16_t p,
+ ConnectionCodec::Factory* f,
+ ConnectFailedCallback failed)
+{
+ ::addrinfo *res;
+ ::addrinfo hints = {};
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ stringstream ss; ss << p;
+ string port = ss.str();
+ int n = ::getaddrinfo(host.c_str(), port.c_str(), &hints, &res);
+ if (n<0) {
+ throw Exception(QPID_MSG("Rdma: Cannot resolve " << host << ": " << ::gai_strerror(n)));
+ }
+
+ Rdma::Connector* c =
+ new Rdma::Connector(
+ *res->ai_addr,
+ Rdma::ConnectionParams(8000, Rdma::DEFAULT_WR_ENTRIES),
+ boost::bind(&RdmaIOProtocolFactory::connected, this, poller, _1, _2, f),
+ boost::bind(&RdmaIOProtocolFactory::connectionError, this, _1, _2),
+ boost::bind(&RdmaIOProtocolFactory::disconnected, this, _1),
+ boost::bind(&RdmaIOProtocolFactory::rejected, this, _1, _2, failed));
+
+ c->start(poller);
+}
+
+}} // namespace qpid::sys
diff --git a/RC9/qpid/cpp/src/qpid/sys/Runnable.cpp b/RC9/qpid/cpp/src/qpid/sys/Runnable.cpp
new file mode 100644
index 0000000000..30122c682f
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/Runnable.cpp
@@ -0,0 +1,32 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "Runnable.h"
+#include <boost/bind.hpp>
+
+namespace qpid {
+namespace sys {
+
+Runnable::~Runnable() {}
+
+Runnable::Functor Runnable::functor()
+{
+ return boost::bind(&Runnable::run, this);
+}
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/sys/Runnable.h b/RC9/qpid/cpp/src/qpid/sys/Runnable.h
new file mode 100644
index 0000000000..fb3927c612
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/Runnable.h
@@ -0,0 +1,50 @@
+#ifndef _Runnable_
+#define _Runnable_
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <boost/function.hpp>
+
+namespace qpid {
+namespace sys {
+
+/**
+ * Interface for objects that can be run, e.g. in a thread.
+ */
+class Runnable
+{
+ public:
+ /** Type to represent a runnable as a Functor */
+ typedef boost::function0<void> Functor;
+
+ virtual ~Runnable();
+
+ /** Derived classes override run(). */
+ virtual void run() = 0;
+
+ /** Create a functor object that will call this->run(). */
+ Functor functor();
+};
+
+}}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/sys/ScopedIncrement.h b/RC9/qpid/cpp/src/qpid/sys/ScopedIncrement.h
new file mode 100644
index 0000000000..8645ab2484
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/ScopedIncrement.h
@@ -0,0 +1,67 @@
+#ifndef _posix_ScopedIncrement_h
+#define _posix_ScopedIncrement_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <boost/noncopyable.hpp>
+#include <boost/function.hpp>
+
+namespace qpid {
+namespace sys {
+
+/**
+ * Increment counter in constructor and decrement in destructor.
+ * Optionally call a function if the decremented counter value is 0.
+ * Note the function must not throw, it is called in the destructor.
+ */
+template <class T, class F=boost::function<void()> >
+class ScopedIncrement : boost::noncopyable
+{
+ public:
+ ScopedIncrement(T& c, F f=0)
+ : count(c), callback(f) { ++count; }
+ ~ScopedIncrement() { if (--count == 0 && callback) callback(); }
+
+ private:
+ T& count;
+ F callback;
+};
+
+
+/** Decrement counter in constructor and increment in destructor. */
+template <class T>
+class ScopedDecrement : boost::noncopyable
+{
+ public:
+ ScopedDecrement(T& c) : count(c) { value = --count; }
+ ~ScopedDecrement() { ++count; }
+
+ /** Return the value after the decrement. */
+ operator long() { return value; }
+
+ private:
+ T& count;
+ long value;
+};
+
+
+}}
+
+
+#endif // _posix_ScopedIncrement_h
diff --git a/RC9/qpid/cpp/src/qpid/sys/Semaphore.h b/RC9/qpid/cpp/src/qpid/sys/Semaphore.h
new file mode 100644
index 0000000000..3efb7ce2df
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/Semaphore.h
@@ -0,0 +1,67 @@
+#ifndef _sys_Semaphore_h
+#define _sys_Semaphore_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "Monitor.h"
+
+namespace qpid {
+namespace sys {
+
+class Semaphore
+{
+public:
+ Semaphore(uint c = 1) : count(c) {}
+
+ void lock() { acquire(); }
+ void unlock() { release(); }
+ bool trylock() { return tryAcquire(); }
+
+ bool tryAcquire()
+ {
+ Monitor::ScopedLock l(monitor);
+ if (count) {
+ count--;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ void acquire()
+ {
+ Monitor::ScopedLock l(monitor);
+ while (count == 0) monitor.wait();
+ count--;
+ }
+
+ void release()
+ {
+ Monitor::ScopedLock l(monitor);
+ if (!count++) monitor.notifyAll();
+ }
+
+private:
+ Monitor monitor;
+ uint count;
+};
+
+}}
+
+#endif /*!_sys_Semaphore_h*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/Shlib.cpp b/RC9/qpid/cpp/src/qpid/sys/Shlib.cpp
new file mode 100644
index 0000000000..8fd3f42cc6
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/Shlib.cpp
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Shlib.h"
+
+#include "qpid/log/Statement.h"
+
+namespace qpid {
+namespace sys {
+
+AutoShlib::~AutoShlib() throw() {
+ try {
+ unload();
+ } catch(const std::exception& e) {
+ QPID_LOG(error, "Unloading shared library: " << e.what());
+ }
+}
+
+// Note: Other functions are defined in apr/Shlib.cpp or posix/Shlib.cpp.
+
+}} // namespace qpid::sys
diff --git a/RC9/qpid/cpp/src/qpid/sys/Shlib.h b/RC9/qpid/cpp/src/qpid/sys/Shlib.h
new file mode 100644
index 0000000000..a6d94b42d4
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/Shlib.h
@@ -0,0 +1,75 @@
+#ifndef QPID_SYS_SHLIB_H
+#define QPID_SYS_SHLIB_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <boost/noncopyable.hpp>
+#include <iostream>
+
+namespace qpid {
+namespace sys {
+
+/** Encapsulates a shared library handle.
+ *@see AutoShlib
+ */
+class Shlib {
+ public:
+ /** Load a shared library */
+ Shlib(const char* libname) { load(libname); }
+
+ /** Load a shared library */
+ Shlib(const std::string& libname) { load(libname.c_str()); }
+
+ /** Unload shared library. */
+ void unload();
+
+ /** Look up symbol. */
+ void* getSymbol(const char* symbol);
+
+ /** Look up symbol in shared library, cast it to the desired
+ * pointer type, void* by default.
+ */
+ template <class T>
+ T getSymbol(const char* symbol) {
+ // Double cast avoids warning about casting object to function pointer
+ return reinterpret_cast<T>(reinterpret_cast<intptr_t>(
+ this->getSymbol(symbol)));
+ }
+
+ private:
+ void* handle;
+ void load(const char* libname);
+};
+
+/** A shared library handle that unloads the shlib in it's dtor */
+class AutoShlib : public Shlib {
+ public:
+ /** Load shared library */
+ AutoShlib(const std::string& libname) : Shlib(libname) {}
+ /** Calls unload() */
+ ~AutoShlib() throw();
+};
+
+
+}} // namespace qpid::sys
+
+#endif /*!QPID_SYS_SHLIB_H*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/ShutdownHandler.h b/RC9/qpid/cpp/src/qpid/sys/ShutdownHandler.h
new file mode 100644
index 0000000000..88baecb5b6
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/ShutdownHandler.h
@@ -0,0 +1,37 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _ShutdownHandler_
+#define _ShutdownHandler_
+
+namespace qpid {
+namespace sys {
+
+ class ShutdownHandler
+ {
+ public:
+ virtual void shutdown() = 0;
+ virtual ~ShutdownHandler(){}
+ };
+
+}
+}
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/sys/Socket.h b/RC9/qpid/cpp/src/qpid/sys/Socket.h
new file mode 100644
index 0000000000..ae48b8104d
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/Socket.h
@@ -0,0 +1,110 @@
+#ifndef _sys_Socket_h
+#define _sys_Socket_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "IOHandle.h"
+#include "qpid/sys/IntegerTypes.h"
+
+#include <string>
+
+struct sockaddr;
+
+namespace qpid {
+namespace sys {
+
+class Duration;
+
+class Socket : public IOHandle
+{
+public:
+ /** Create a socket wrapper for descriptor. */
+ Socket();
+
+ /** Create an initialized TCP socket */
+ void createTcp() const;
+
+ /** Set timeout for read and write */
+ void setTimeout(const Duration& interval) const;
+
+ /** Set socket non blocking */
+ void setNonblocking() const;
+
+ void connect(const std::string& host, uint16_t port) const;
+
+ void close() const;
+
+ /** Bind to a port and start listening.
+ *@param port 0 means choose an available port.
+ *@param backlog maximum number of pending connections.
+ *@return The bound port.
+ */
+ int listen(uint16_t port = 0, int backlog = 10) const;
+
+ /** Returns the "socket name" ie the address bound to
+ * the near end of the socket
+ */
+ std::string getSockname() const;
+
+ /** Returns the "peer name" ie the address bound to
+ * the remote end of the socket
+ */
+ std::string getPeername() const;
+
+ /**
+ * Returns an address (host and port) for the remote end of the
+ * socket
+ */
+ std::string getPeerAddress() const;
+ /**
+ * Returns an address (host and port) for the local end of the
+ * socket
+ */
+ std::string getLocalAddress() const;
+
+ uint16_t getLocalPort() const;
+ uint16_t getRemotePort() const;
+
+ /**
+ * Returns the error code stored in the socket. This may be used
+ * to determine the result of a non-blocking connect.
+ */
+ int getError() const;
+
+ /** Accept a connection from a socket that is already listening
+ * and has an incoming connection
+ */
+ Socket* accept(struct sockaddr *addr, socklen_t *addrlen) const;
+
+ // TODO The following are raw operations, maybe they need better wrapping?
+ int read(void *buf, size_t count) const;
+ int write(const void *buf, size_t count) const;
+
+ void setTcpNoDelay(bool nodelay) const;
+
+private:
+ Socket(IOHandlePrivate*);
+ mutable std::string connectname;
+};
+
+}}
+#endif /*!_sys_Socket_h*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/SslPlugin.cpp b/RC9/qpid/cpp/src/qpid/sys/SslPlugin.cpp
new file mode 100644
index 0000000000..14052c2ee4
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/SslPlugin.cpp
@@ -0,0 +1,184 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "ProtocolFactory.h"
+
+#include "qpid/Plugin.h"
+#include "qpid/sys/ssl/check.h"
+#include "qpid/sys/ssl/util.h"
+#include "qpid/sys/ssl/SslHandler.h"
+#include "qpid/sys/ssl/SslIo.h"
+#include "qpid/sys/ssl/SslSocket.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/log/Statement.h"
+
+#include <boost/bind.hpp>
+#include <memory>
+
+
+namespace qpid {
+namespace sys {
+
+struct SslServerOptions : ssl::SslOptions
+{
+ uint16_t port;
+ bool clientAuth;
+
+ SslServerOptions() : port(5671),
+ clientAuth(false)
+ {
+ addOptions()
+ ("ssl-port", optValue(port, "PORT"), "Port on which to listen for SSL connections")
+ ("ssl-require-client-authentication", optValue(clientAuth),
+ "Forces clients to authenticate in order to establish an SSL connection");
+ }
+};
+
+class SslProtocolFactory : public ProtocolFactory {
+ const bool tcpNoDelay;
+ qpid::sys::ssl::SslSocket listener;
+ const uint16_t listeningPort;
+ std::auto_ptr<qpid::sys::ssl::SslAcceptor> acceptor;
+
+ public:
+ SslProtocolFactory(const SslServerOptions&, int backlog, bool nodelay);
+ void accept(Poller::shared_ptr, ConnectionCodec::Factory*);
+ void connect(Poller::shared_ptr, const std::string& host, int16_t port,
+ ConnectionCodec::Factory*,
+ boost::function2<void, int, std::string> failed);
+
+ uint16_t getPort() const;
+ std::string getHost() const;
+ bool supports(const std::string& capability);
+
+ private:
+ void established(Poller::shared_ptr, const qpid::sys::ssl::SslSocket&, ConnectionCodec::Factory*,
+ bool isClient);
+};
+
+// Static instance to initialise plugin
+static struct SslPlugin : public Plugin {
+ SslServerOptions options;
+
+ Options* getOptions() { return &options; }
+
+ ~SslPlugin() { ssl::shutdownNSS(); }
+
+ void earlyInitialize(Target&) {
+ }
+
+ void initialize(Target& target) {
+ broker::Broker* broker = dynamic_cast<broker::Broker*>(&target);
+ // Only provide to a Broker
+ if (broker) {
+ if (options.certDbPath.empty()) {
+ QPID_LOG(warning, "SSL plugin not enabled, you must set --qpid-ssl-cert-db to enable it.");
+ } else {
+ try {
+ ssl::initNSS(options, true);
+
+ const broker::Broker::Options& opts = broker->getOptions();
+ ProtocolFactory::shared_ptr protocol(new SslProtocolFactory(options,
+ opts.connectionBacklog, opts.tcpNoDelay));
+ QPID_LOG(notice, "Listening for SSL connections on TCP port " << protocol->getPort());
+ broker->registerProtocolFactory("ssl", protocol);
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Failed to initialise SSL plugin: " << e.what());
+ }
+ }
+ }
+ }
+} sslPlugin;
+
+SslProtocolFactory::SslProtocolFactory(const SslServerOptions& options, int backlog, bool nodelay) :
+ tcpNoDelay(nodelay), listeningPort(listener.listen(options.port, backlog, options.certName, options.clientAuth))
+{}
+
+void SslProtocolFactory::established(Poller::shared_ptr poller, const qpid::sys::ssl::SslSocket& s,
+ ConnectionCodec::Factory* f, bool isClient) {
+ qpid::sys::ssl::SslHandler* async = new qpid::sys::ssl::SslHandler(s.getPeerAddress(), f);
+
+ if (tcpNoDelay) {
+ s.setTcpNoDelay(tcpNoDelay);
+ QPID_LOG(info, "Set TCP_NODELAY on connection to " << s.getPeerAddress());
+ }
+
+ if (isClient)
+ async->setClient();
+ qpid::sys::ssl::SslIO* aio = new qpid::sys::ssl::SslIO(s,
+ boost::bind(&qpid::sys::ssl::SslHandler::readbuff, async, _1, _2),
+ boost::bind(&qpid::sys::ssl::SslHandler::eof, async, _1),
+ boost::bind(&qpid::sys::ssl::SslHandler::disconnect, async, _1),
+ boost::bind(&qpid::sys::ssl::SslHandler::closedSocket, async, _1, _2),
+ boost::bind(&qpid::sys::ssl::SslHandler::nobuffs, async, _1),
+ boost::bind(&qpid::sys::ssl::SslHandler::idle, async, _1));
+
+ async->init(aio, 4);
+ aio->start(poller);
+}
+
+uint16_t SslProtocolFactory::getPort() const {
+ return listeningPort; // Immutable no need for lock.
+}
+
+std::string SslProtocolFactory::getHost() const {
+ return listener.getSockname();
+}
+
+void SslProtocolFactory::accept(Poller::shared_ptr poller,
+ ConnectionCodec::Factory* fact) {
+ acceptor.reset(
+ new qpid::sys::ssl::SslAcceptor(listener,
+ boost::bind(&SslProtocolFactory::established, this, poller, _1, fact, false)));
+ acceptor->start(poller);
+}
+
+void SslProtocolFactory::connect(
+ Poller::shared_ptr poller,
+ const std::string& host, int16_t port,
+ ConnectionCodec::Factory* fact,
+ ConnectFailedCallback failed)
+{
+ // Note that the following logic does not cause a memory leak.
+ // The allocated Socket is freed either by the SslConnector
+ // upon connection failure or by the SslIoHandle upon connection
+ // shutdown. The allocated SslConnector frees itself when it
+ // is no longer needed.
+
+ qpid::sys::ssl::SslSocket* socket = new qpid::sys::ssl::SslSocket();
+ new qpid::sys::ssl::SslConnector (*socket, poller, host, port,
+ boost::bind(&SslProtocolFactory::established, this, poller, _1, fact, true),
+ failed);
+}
+
+namespace
+{
+const std::string SSL = "ssl";
+}
+
+bool SslProtocolFactory::supports(const std::string& capability)
+{
+ std::string s = capability;
+ transform(s.begin(), s.end(), s.begin(), tolower);
+ return s == SSL;
+}
+
+}} // namespace qpid::sys
diff --git a/RC9/qpid/cpp/src/qpid/sys/StateMonitor.h b/RC9/qpid/cpp/src/qpid/sys/StateMonitor.h
new file mode 100644
index 0000000000..5a92756f3a
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/StateMonitor.h
@@ -0,0 +1,78 @@
+#ifndef QPID_SYS_STATEMONITOR_H
+#define QPID_SYS_STATEMONITOR_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/sys/Waitable.h"
+
+#include <bitset>
+
+namespace qpid {
+namespace sys {
+
+/**
+ * A monitor with an enum state value.
+ *
+ *@param Enum: enum type to use for states.
+ *@param EnumMax: Highest enum value.
+ */
+template <class Enum, size_t MaxEnum>
+class StateMonitor : public Waitable
+{
+ public:
+ struct Set : public std::bitset<MaxEnum + 1> {
+ Set() {}
+ Set(Enum s) { set(s); }
+ Set(Enum s, Enum t) { set(s).set(t); }
+ Set(Enum s, Enum t, Enum u) { set(s).set(t).set(u); }
+ Set(Enum s, Enum t, Enum u, Enum v) { set(s).set(t).set(u).set(v); }
+ };
+
+
+ StateMonitor(Enum initial) { state=initial; }
+
+ /** @pre Caller holds a ScopedLock. */
+ void set(Enum s) { state=s; notifyAll(); }
+ /** @pre Caller holds a ScopedLock. */
+ StateMonitor& operator=(Enum s) { set(s); return *this; }
+
+ /** @pre Caller holds a ScopedLock. */
+ Enum get() const { return state; }
+ /** @pre Caller holds a ScopedLock. */
+ operator Enum() const { return state; }
+
+ /** @pre Caller holds a ScopedLock */
+ void waitFor(Enum s) { ScopedWait(*this); while (s != state) wait(); }
+ /** @pre Caller holds a ScopedLock */
+ void waitFor(Set s) { ScopedWait(*this); while (!s.test(state)) wait(); }
+ /** @pre Caller holds a ScopedLock */
+ void waitNot(Enum s) { ScopedWait(*this); while (s == state) wait(); }
+ /** @pre Caller holds a ScopedLock */
+ void waitNot(Set s) { ScopedWait(*this); while (s.test(state)) wait(); }
+
+ private:
+ Enum state;
+};
+
+}}
+
+
+#endif /*!QPID_SYS_STATEMONITOR_H*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/StrError.h b/RC9/qpid/cpp/src/qpid/sys/StrError.h
new file mode 100644
index 0000000000..3843f2abe1
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/StrError.h
@@ -0,0 +1,35 @@
+#ifndef _sys_StrError_h
+#define _sys_StrError_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <string>
+
+namespace qpid {
+namespace sys {
+
+/** Get the error message for a system number err, e.g. errno. */
+std::string strError(int err);
+
+}} // namespace qpid
+
+#endif // _sys_StrError_h
diff --git a/RC9/qpid/cpp/src/qpid/sys/SystemInfo.h b/RC9/qpid/cpp/src/qpid/sys/SystemInfo.h
new file mode 100644
index 0000000000..d43fe34b04
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/SystemInfo.h
@@ -0,0 +1,79 @@
+#ifndef QPID_SYS_SYSTEMINFO_H
+#define QPID_SYS_SYSTEMINFO_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/IntegerTypes.h"
+#include "qpid/Address.h"
+
+namespace qpid {
+namespace sys {
+
+/**
+ * Retrieve information about the system we are running on.
+ * Results may be dependent on OS/hardware.
+ */
+namespace SystemInfo {
+ /**
+ * Estimate available concurrency, e.g. number of CPU cores.
+ * -1 means estimate not available on this platform.
+ */
+ long concurrency();
+
+ /**
+ * Get the local host name and set it in the specified TcpAddress.
+ * Returns false if it can't be obtained and sets errno to any error value.
+ */
+ bool getLocalHostname (TcpAddress &address);
+
+ void getLocalIpAddresses (uint16_t port, std::vector<Address> &addrList);
+
+ /**
+ * Retrieve system identifiers and versions. This is information that can
+ * generally be retrieved via POSIX uname().
+ *
+ * @param osName Receives the OS name; e.g., GNU/Linux or Windows
+ * @param nodeName Receives the nodename. This may or may not match the
+ * set hostname from getLocalHostname().
+ * @param release Receives the OS release identifier.
+ * @param version Receives the OS release version (kernel, build, sp, etc.)
+ * @param machine Receives the hardware type.
+ */
+ void getSystemId (std::string &osName,
+ std::string &nodeName,
+ std::string &release,
+ std::string &version,
+ std::string &machine);
+
+ /**
+ * Get the process ID of the current process.
+ */
+ uint32_t getProcessId();
+
+ /**
+ * Get the process ID of the parent of the current process.
+ */
+ uint32_t getParentProcessId();
+
+
+}}} // namespace qpid::sys::SystemInfo
+
+#endif /*!QPID_SYS_SYSTEMINFO_H*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/TCPIOPlugin.cpp b/RC9/qpid/cpp/src/qpid/sys/TCPIOPlugin.cpp
new file mode 100644
index 0000000000..be091f86d8
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/TCPIOPlugin.cpp
@@ -0,0 +1,146 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "ProtocolFactory.h"
+#include "AsynchIOHandler.h"
+#include "AsynchIO.h"
+
+#include "qpid/Plugin.h"
+#include "qpid/sys/Socket.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/log/Statement.h"
+
+#include <boost/bind.hpp>
+#include <memory>
+
+namespace qpid {
+namespace sys {
+
+class AsynchIOProtocolFactory : public ProtocolFactory {
+ const bool tcpNoDelay;
+ Socket listener;
+ const uint16_t listeningPort;
+ std::auto_ptr<AsynchAcceptor> acceptor;
+
+ public:
+ AsynchIOProtocolFactory(int16_t port, int backlog, bool nodelay);
+ void accept(Poller::shared_ptr, ConnectionCodec::Factory*);
+ void connect(Poller::shared_ptr, const std::string& host, int16_t port,
+ ConnectionCodec::Factory*,
+ boost::function2<void, int, std::string> failed);
+
+ uint16_t getPort() const;
+ std::string getHost() const;
+
+ private:
+ void established(Poller::shared_ptr, const Socket&, ConnectionCodec::Factory*,
+ bool isClient);
+};
+
+// Static instance to initialise plugin
+static class TCPIOPlugin : public Plugin {
+ void earlyInitialize(Target&) {
+ }
+
+ void initialize(Target& target) {
+ broker::Broker* broker = dynamic_cast<broker::Broker*>(&target);
+ // Only provide to a Broker
+ if (broker) {
+ const broker::Broker::Options& opts = broker->getOptions();
+ if (opts.requireEncrypted) {
+ QPID_LOG(info, "Not accepting unencrypted connections on TCP");
+ } else {
+ ProtocolFactory::shared_ptr protocol(new AsynchIOProtocolFactory(opts.port, opts.connectionBacklog,
+ opts.tcpNoDelay));
+ QPID_LOG(notice, "Listening on TCP port " << protocol->getPort());
+ broker->registerProtocolFactory("tcp", protocol);
+ }
+ }
+ }
+} tcpPlugin;
+
+AsynchIOProtocolFactory::AsynchIOProtocolFactory(int16_t port, int backlog, bool nodelay) :
+ tcpNoDelay(nodelay), listeningPort(listener.listen(port, backlog))
+{}
+
+void AsynchIOProtocolFactory::established(Poller::shared_ptr poller, const Socket& s,
+ ConnectionCodec::Factory* f, bool isClient) {
+ AsynchIOHandler* async = new AsynchIOHandler(s.getPeerAddress(), f);
+
+ if (tcpNoDelay) {
+ s.setTcpNoDelay(tcpNoDelay);
+ QPID_LOG(info, "Set TCP_NODELAY on connection to " << s.getPeerAddress());
+ }
+
+ if (isClient)
+ async->setClient();
+ AsynchIO* aio = AsynchIO::create
+ (s,
+ boost::bind(&AsynchIOHandler::readbuff, async, _1, _2),
+ boost::bind(&AsynchIOHandler::eof, async, _1),
+ boost::bind(&AsynchIOHandler::disconnect, async, _1),
+ boost::bind(&AsynchIOHandler::closedSocket, async, _1, _2),
+ boost::bind(&AsynchIOHandler::nobuffs, async, _1),
+ boost::bind(&AsynchIOHandler::idle, async, _1));
+
+ async->init(aio, 4);
+ aio->start(poller);
+}
+
+uint16_t AsynchIOProtocolFactory::getPort() const {
+ return listeningPort; // Immutable no need for lock.
+}
+
+std::string AsynchIOProtocolFactory::getHost() const {
+ return listener.getSockname();
+}
+
+void AsynchIOProtocolFactory::accept(Poller::shared_ptr poller,
+ ConnectionCodec::Factory* fact) {
+ acceptor.reset(
+ new AsynchAcceptor(listener,
+ boost::bind(&AsynchIOProtocolFactory::established, this, poller, _1, fact, false)));
+ acceptor->start(poller);
+}
+
+void AsynchIOProtocolFactory::connect(
+ Poller::shared_ptr poller,
+ const std::string& host, int16_t port,
+ ConnectionCodec::Factory* fact,
+ ConnectFailedCallback failed)
+{
+ // Note that the following logic does not cause a memory leak.
+ // The allocated Socket is freed either by the AsynchConnector
+ // upon connection failure or by the AsynchIO upon connection
+ // shutdown. The allocated AsynchConnector frees itself when it
+ // is no longer needed.
+
+ Socket* socket = new Socket();
+ AsynchConnector::create (*socket,
+ poller,
+ host,
+ port,
+ boost::bind(&AsynchIOProtocolFactory::established,
+ this, poller, _1, fact, true),
+ failed);
+}
+
+}} // namespace qpid::sys
diff --git a/RC9/qpid/cpp/src/qpid/sys/Thread.h b/RC9/qpid/cpp/src/qpid/sys/Thread.h
new file mode 100644
index 0000000000..2fd59621d8
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/Thread.h
@@ -0,0 +1,62 @@
+#ifndef _sys_Thread_h
+#define _sys_Thread_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <boost/shared_ptr.hpp>
+
+#ifdef _WIN32
+# define QPID_TSS __declspec(thread)
+#elif defined (gcc)
+# define QPID_TSS __thread
+#else
+# define QPID_TSS
+#endif
+
+namespace qpid {
+namespace sys {
+
+class Runnable;
+class ThreadPrivate;
+
+class Thread
+{
+ boost::shared_ptr<ThreadPrivate> impl;
+
+ public:
+ Thread();
+ explicit Thread(qpid::sys::Runnable*);
+ explicit Thread(qpid::sys::Runnable&);
+
+ void join();
+
+ unsigned long id();
+
+ static Thread current();
+
+ /** ID of current thread for logging.
+ * Workaround for broken Thread::current() in APR
+ */
+ static unsigned long logId() { return current().id(); }
+};
+
+}}
+#endif /*!_sys_Thread_h*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/Time.h b/RC9/qpid/cpp/src/qpid/sys/Time.h
new file mode 100644
index 0000000000..d39be95434
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/Time.h
@@ -0,0 +1,168 @@
+#ifndef _sys_Time_h
+#define _sys_Time_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/IntegerTypes.h"
+/*
+ * The platform defines its notion of time as a TimePrivate type. The
+ * platform's implementation knows how to handle this type.
+ */
+#if defined (_WIN32)
+# include "windows/Time.h"
+#else
+# include "posix/Time.h"
+#endif
+
+#include <limits>
+#include <iosfwd>
+
+namespace qpid {
+namespace sys {
+
+class Duration;
+
+/**
+ * @class AbsTime
+ *
+ * Class to represent an instant in time.
+ *
+ * The time resolution is in nanosecs, and this is held with 64 bits
+ * giving a total time span from about 25 million years ago to 25 million
+ * years hence. As an aside the internal time can sensibly be negative
+ * meaning before the epoch (probably 1/1/1970 although this class doesn't
+ * care).
+ *
+ * The AbsTime class is a value class and so you don't need to add any
+ * accessors to its internal state. If you think you want to replace its value,
+ * you need to construct a new AbsTime and assign it, viz:
+ *
+ * AbsTime when = AbsTime::now();
+ * ...
+ * when = AbsTime(when, 2*TIME_SEC); // Advance timer 2 secs
+ *
+ * If for some reason you need access to the internal nanosec value you need
+ * to convert the AbsTime to a Duration and use its conversion to int64_t, viz:
+ *
+ * AbsTime now = AbsTime::now();
+ *
+ * int64_t ns = Duration(now);
+ *
+ * However note that the nanosecond value that is returned here is not
+ * defined to be anything in particular and could vary from platform to
+ * platform.
+ *
+ * There are some sensible operations that are currently missing from
+ * AbsTime, but nearly all that's needed can be done with a mixture of
+ * AbsTimes and Durations.
+ *
+ * For example, convenience operators to add a Duration and AbsTime returning
+ * an AbsTime would fit here (although you can already perform the operation
+ * with one of the AbsTime constructors). However trying to add 2 AbsTimes
+ * doesn't make sense.
+ */
+class AbsTime {
+ friend class Duration;
+
+ TimePrivate timepoint;
+
+public:
+ inline AbsTime() {}
+ AbsTime(const AbsTime& time0, const Duration& duration);
+ // Default assignment operation fine
+ // Default copy constructor fine
+
+ static AbsTime now();
+ static AbsTime FarFuture();
+ const TimePrivate& getPrivate(void) const { return timepoint; }
+ bool operator==(const AbsTime& t) const { return t.timepoint == timepoint; }
+ template <class S> void serialize(S& s) { s(timepoint); }
+
+ friend bool operator<(const AbsTime& a, const AbsTime& b);
+ friend bool operator>(const AbsTime& a, const AbsTime& b);
+ friend std::ostream& operator << (std::ostream&, const AbsTime&);
+};
+
+std::ostream& operator << (std::ostream&, const AbsTime&);
+
+/**
+ * @class Duration
+ * Class to represent the duration between instants of time.
+ *
+ * As AbsTime, this class also uses nanosecs for its time
+ * resolution where possible. For the most part a duration can be dealt
+ * with like a 64 bit integer, and indeed there is an implicit conversion which
+ * makes this quite convenient.
+ */
+class Duration {
+ static int64_t max() { return std::numeric_limits<int64_t>::max(); }
+ int64_t nanosecs;
+
+ friend class AbsTime;
+
+public:
+ inline Duration(int64_t time0);
+ explicit Duration(const AbsTime& time0);
+ explicit Duration(const AbsTime& start, const AbsTime& finish);
+ inline operator int64_t() const;
+};
+
+std::ostream& operator << (std::ostream&, const Duration&);
+
+inline AbsTime now() { return AbsTime::now(); }
+
+inline bool operator<(const AbsTime& a, const AbsTime& b)
+{ return a.timepoint < b.timepoint; }
+inline bool operator>(const AbsTime& a, const AbsTime& b)
+{ return a.timepoint > b.timepoint; }
+
+Duration::Duration(int64_t time0) :
+ nanosecs(time0)
+{}
+
+Duration::operator int64_t() const
+{ return nanosecs; }
+
+/** Nanoseconds per second. */
+const Duration TIME_SEC = 1000*1000*1000;
+/** Nanoseconds per millisecond */
+const Duration TIME_MSEC = 1000*1000;
+/** Nanoseconds per microseconds. */
+const Duration TIME_USEC = 1000;
+/** Nanoseconds per nanosecond. */
+const Duration TIME_NSEC = 1;
+
+/** Value to represent an infinite timeout */
+const Duration TIME_INFINITE = std::numeric_limits<int64_t>::max();
+
+/** Time greater than any other time */
+const AbsTime FAR_FUTURE = AbsTime::FarFuture();
+
+/** Portable sleep for a number of seconds */
+void sleep(int secs);
+
+/** Portable sleep for a number of microseconds */
+void usleep(uint64_t usecs);
+
+}}
+
+#endif /*!_sys_Time_h*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/TimeoutHandler.h b/RC9/qpid/cpp/src/qpid/sys/TimeoutHandler.h
new file mode 100644
index 0000000000..0c10709bbf
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/TimeoutHandler.h
@@ -0,0 +1,39 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _TimeoutHandler_
+#define _TimeoutHandler_
+
+namespace qpid {
+namespace sys {
+
+ class TimeoutHandler
+ {
+ public:
+ virtual void idleOut() = 0;
+ virtual void idleIn() = 0;
+ virtual ~TimeoutHandler(){}
+ };
+
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/sys/Waitable.h b/RC9/qpid/cpp/src/qpid/sys/Waitable.h
new file mode 100644
index 0000000000..7701b6f97d
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/Waitable.h
@@ -0,0 +1,114 @@
+#ifndef QPID_SYS_WAITABLE_H
+#define QPID_SYS_WAITABLE_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Monitor.h"
+#include "qpid/sys/ExceptionHolder.h"
+#include <assert.h>
+
+namespace qpid {
+namespace sys {
+
+/**
+ * A monitor that keeps track of waiting threads. Threads declare a
+ * ScopedWait around wait() inside a ScopedLock to be considered
+ * waiters.
+ *
+ * Allows waiting threads to be interrupted by an exception.
+ */
+class Waitable : public Monitor {
+ public:
+ Waitable() : waiters(0) {}
+
+ ~Waitable() { assert(waiters == 0); }
+
+ /** Use this inside a scoped lock around the
+ * call to wait() to be counted as a waiter.
+ */
+ struct ScopedWait {
+ Waitable& w;
+ ScopedWait(Waitable& w_) : w(w_) { ++w.waiters; }
+ ~ScopedWait() { if (--w.waiters==0) w.notifyAll(); }
+ };
+
+ /** Block till there are no more waiters in ScopedWaits.
+ * waitWaiters() does not raise an exception even if waiters
+ * were interrupted by one.
+ *@pre Must be called inside a ScopedLock but NOT a ScopedWait.
+ */
+ void waitWaiters() {
+ while (waiters != 0)
+ Monitor::wait();
+ }
+
+ /** Returns the number of outstanding ScopedWaits.
+ * Must be called with the lock held.
+ */
+ size_t hasWaiters() const {
+ return waiters;
+ }
+
+ /** Set an execption to interrupt waiters in ScopedWait.
+ * Must be called with the lock held.
+ */
+ void setException(const ExceptionHolder& e) {
+ exception = e;
+ notifyAll();
+
+ }
+
+ /** True if the waitable has an exception */
+ bool hasException() const { return exception; }
+
+ /** Clear the exception if any */
+ void resetException() { exception.reset(); }
+
+ /** Throws an exception if one is set before or during the wait. */
+ void wait() {
+ ExCheck e(exception);
+ Monitor::wait();
+ }
+
+ /** Throws an exception if one is set before or during the wait. */
+ bool wait(const AbsTime& absoluteTime) {
+ ExCheck e(exception);
+ return Monitor::wait(absoluteTime);
+ }
+
+ private:
+ struct ExCheck {
+ const ExceptionHolder& exception;
+ ExCheck(const ExceptionHolder& e) : exception(e) { e.raise(); }
+ ~ExCheck() { exception.raise(); }
+ };
+
+ size_t waiters;
+ ExceptionHolder exception;
+
+ friend struct ScopedWait;
+};
+
+}} // namespace qpid::sys
+
+
+
+#endif /*!QPID_SYS_WAITABLE_H*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/apr/APRBase.cpp b/RC9/qpid/cpp/src/qpid/sys/apr/APRBase.cpp
new file mode 100644
index 0000000000..724c489303
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/apr/APRBase.cpp
@@ -0,0 +1,89 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <iostream>
+#include "qpid/log/Statement.h"
+#include "APRBase.h"
+
+using namespace qpid::sys;
+
+APRBase* APRBase::instance = 0;
+
+APRBase* APRBase::getInstance(){
+ if(instance == 0){
+ instance = new APRBase();
+ }
+ return instance;
+}
+
+
+APRBase::APRBase() : count(0){
+ apr_initialize();
+ CHECK_APR_SUCCESS(apr_pool_create(&pool, 0));
+ CHECK_APR_SUCCESS(apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_NESTED, pool));
+}
+
+APRBase::~APRBase(){
+ CHECK_APR_SUCCESS(apr_thread_mutex_destroy(mutex));
+ apr_pool_destroy(pool);
+ apr_terminate();
+}
+
+bool APRBase::_increment(){
+ bool deleted(false);
+ CHECK_APR_SUCCESS(apr_thread_mutex_lock(mutex));
+ if(this == instance){
+ count++;
+ }else{
+ deleted = true;
+ }
+ CHECK_APR_SUCCESS(apr_thread_mutex_unlock(mutex));
+ return !deleted;
+}
+
+void APRBase::_decrement(){
+ APRBase* copy = 0;
+ CHECK_APR_SUCCESS(apr_thread_mutex_lock(mutex));
+ if(--count == 0){
+ copy = instance;
+ instance = 0;
+ }
+ CHECK_APR_SUCCESS(apr_thread_mutex_unlock(mutex));
+ if(copy != 0){
+ delete copy;
+ }
+}
+
+void APRBase::increment(){
+ int count = 0;
+ while(count++ < 2 && !getInstance()->_increment())
+ QPID_LOG(warning, "APR initialization triggered concurrently with termination.");
+}
+
+void APRBase::decrement(){
+ getInstance()->_decrement();
+}
+
+std::string qpid::sys::get_desc(apr_status_t status){
+ const int size = 50;
+ char tmp[size];
+ return std::string(apr_strerror(status, tmp, size));
+}
+
diff --git a/RC9/qpid/cpp/src/qpid/sys/apr/APRBase.h b/RC9/qpid/cpp/src/qpid/sys/apr/APRBase.h
new file mode 100644
index 0000000000..7b5644a129
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/apr/APRBase.h
@@ -0,0 +1,74 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _APRBase_
+#define _APRBase_
+
+#include <string>
+#include <apr_thread_mutex.h>
+#include <apr_errno.h>
+
+namespace qpid {
+namespace sys {
+
+ /**
+ * Use of APR libraries necessitates explicit init and terminate
+ * calls. Any class using APR libs should obtain the reference to
+ * this singleton and increment on construction, decrement on
+ * destruction. This class can then correctly initialise apr
+ * before the first use and terminate after the last use.
+ */
+ class APRBase{
+ static APRBase* instance;
+ apr_pool_t* pool;
+ apr_thread_mutex_t* mutex;
+ int count;
+
+ APRBase();
+ ~APRBase();
+ static APRBase* getInstance();
+ bool _increment();
+ void _decrement();
+ public:
+ static void increment();
+ static void decrement();
+ };
+
+ //this is also a convenient place for a helper function for error checking:
+ void check(apr_status_t status, const char* file, const int line);
+ std::string get_desc(apr_status_t status);
+
+#define CHECK_APR_SUCCESS(A) qpid::sys::check(A, __FILE__, __LINE__);
+
+}
+}
+
+// Inlined as it is called *a lot*
+void inline qpid::sys::check(apr_status_t status, const char* file, const int line){
+ if (status != APR_SUCCESS){
+ char tmp[256];
+ throw Exception(QPID_MSG(apr_strerror(status, tmp, size)))
+ }
+}
+
+
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/sys/apr/APRPool.cpp b/RC9/qpid/cpp/src/qpid/sys/apr/APRPool.cpp
new file mode 100644
index 0000000000..e8b71f6e8a
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/apr/APRPool.cpp
@@ -0,0 +1,41 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "APRPool.h"
+#include "APRBase.h"
+#include <boost/pool/detail/singleton.hpp>
+
+using namespace qpid::sys;
+
+APRPool::APRPool(){
+ APRBase::increment();
+ CHECK_APR_SUCCESS(apr_pool_create(&pool, NULL));
+}
+
+APRPool::~APRPool(){
+ apr_pool_destroy(pool);
+ APRBase::decrement();
+}
+
+apr_pool_t* APRPool::get() {
+ return boost::details::pool::singleton_default<APRPool>::instance().pool;
+}
+
diff --git a/RC9/qpid/cpp/src/qpid/sys/apr/APRPool.h b/RC9/qpid/cpp/src/qpid/sys/apr/APRPool.h
new file mode 100644
index 0000000000..da7661fcfa
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/apr/APRPool.h
@@ -0,0 +1,50 @@
+#ifndef _APRPool_
+#define _APRPool_
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <boost/noncopyable.hpp>
+#include <apr_pools.h>
+
+namespace qpid {
+namespace sys {
+/**
+ * Singleton APR memory pool.
+ */
+class APRPool : private boost::noncopyable {
+ public:
+ APRPool();
+ ~APRPool();
+
+ /** Get singleton instance */
+ static apr_pool_t* get();
+
+ private:
+ apr_pool_t* pool;
+};
+
+}}
+
+
+
+
+
+#endif /*!_APRPool_*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/apr/Condition.h b/RC9/qpid/cpp/src/qpid/sys/apr/Condition.h
new file mode 100644
index 0000000000..5e544219ab
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/apr/Condition.h
@@ -0,0 +1,84 @@
+#ifndef _sys_apr_Condition_h
+#define _sys_apr_Condition_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "APRPool.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Time.h"
+
+#include <sys/errno.h>
+#include <boost/noncopyable.hpp>
+#include <apr_thread_cond.h>
+
+namespace qpid {
+namespace sys {
+
+/**
+ * A condition variable for thread synchronization.
+ */
+class Condition
+{
+ public:
+ inline Condition();
+ inline ~Condition();
+ inline void wait(Mutex&);
+ inline bool wait(Mutex&, const AbsTime& absoluteTime);
+ inline void notify();
+ inline void notifyAll();
+
+ private:
+ apr_thread_cond_t* condition;
+};
+
+
+Condition::Condition() {
+ CHECK_APR_SUCCESS(apr_thread_cond_create(&condition, APRPool::get()));
+}
+
+Condition::~Condition() {
+ CHECK_APR_SUCCESS(apr_thread_cond_destroy(condition));
+}
+
+void Condition::wait(Mutex& mutex) {
+ CHECK_APR_SUCCESS(apr_thread_cond_wait(condition, mutex.mutex));
+}
+
+bool Condition::wait(Mutex& mutex, const AbsTime& absoluteTime){
+ // APR uses microseconds.
+ apr_status_t status =
+ apr_thread_cond_timedwait(
+ condition, mutex.mutex, Duration(now(), absoluteTime)/TIME_USEC);
+ if(status != APR_TIMEUP) CHECK_APR_SUCCESS(status);
+ return status == 0;
+}
+
+void Condition::notify(){
+ CHECK_APR_SUCCESS(apr_thread_cond_signal(condition));
+}
+
+void Condition::notifyAll(){
+ CHECK_APR_SUCCESS(apr_thread_cond_broadcast(condition));
+}
+
+}}
+#endif /*!_sys_apr_Condition_h*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/apr/Mutex.h b/RC9/qpid/cpp/src/qpid/sys/apr/Mutex.h
new file mode 100644
index 0000000000..51089c98ff
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/apr/Mutex.h
@@ -0,0 +1,124 @@
+#ifndef _sys_apr_Mutex_h
+#define _sys_apr_Mutex_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "APRBase.h"
+#include "APRPool.h"
+
+#include <boost/noncopyable.hpp>
+#include <apr_thread_mutex.h>
+
+namespace qpid {
+namespace sys {
+
+class Condition;
+
+/**
+ * Mutex lock.
+ */
+class Mutex : private boost::noncopyable {
+ public:
+ typedef ScopedLock<Mutex> ScopedLock;
+ typedef ScopedUnlock<Mutex> ScopedUnlock;
+
+ inline Mutex();
+ inline ~Mutex();
+ inline void lock();
+ inline void unlock();
+ inline bool trylock();
+
+ protected:
+ apr_thread_mutex_t* mutex;
+ friend class Condition;
+};
+
+Mutex::Mutex() {
+ CHECK_APR_SUCCESS(apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_NESTED, APRPool::get()));
+}
+
+Mutex::~Mutex(){
+ CHECK_APR_SUCCESS(apr_thread_mutex_destroy(mutex));
+}
+
+void Mutex::lock() {
+ CHECK_APR_SUCCESS(apr_thread_mutex_lock(mutex));
+}
+void Mutex::unlock() {
+ CHECK_APR_SUCCESS(apr_thread_mutex_unlock(mutex));
+}
+
+bool Mutex::trylock() {
+ return apr_thread_mutex_trylock(mutex) == 0;
+}
+
+
+/**
+ * RW lock.
+ */
+class RWlock : private boost::noncopyable {
+ friend class Condition;
+
+public:
+ typedef ScopedRlock<RWlock> ScopedRlock;
+ typedef ScopedWlock<RWlock> ScopedWlock;
+
+ inline RWlock();
+ inline ~RWlock();
+ inline void wlock(); // will write-lock
+ inline void rlock(); // will read-lock
+ inline void unlock();
+ inline bool trywlock(); // will write-try
+ inline bool tryrlock(); // will read-try
+
+ protected:
+ apr_thread_mutex_t* mutex;
+};
+
+RWlock::RWlock() {
+ CHECK_APR_SUCCESS(apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_NESTED, APRPool::get()));
+}
+
+RWlock::~RWlock(){
+ CHECK_APR_SUCCESS(apr_thread_mutex_destroy(mutex));
+}
+
+void RWlock::wlock() {
+ CHECK_APR_SUCCESS(apr_thread_mutex_lock(mutex));
+}
+
+void RWlock::rlock() {
+ CHECK_APR_SUCCESS(apr_thread_mutex_lock(mutex));
+}
+
+void RWlock::unlock() {
+ CHECK_APR_SUCCESS(apr_thread_mutex_unlock(mutex));
+}
+
+bool RWlock::trywlock() {
+ return apr_thread_mutex_trylock(mutex) == 0;
+}
+
+bool RWlock::tryrlock() {
+ return apr_thread_mutex_trylock(mutex) == 0;
+}
+
+
+}}
+#endif /*!_sys_apr_Mutex_h*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/apr/Shlib.cpp b/RC9/qpid/cpp/src/qpid/sys/apr/Shlib.cpp
new file mode 100644
index 0000000000..b0ba706713
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/apr/Shlib.cpp
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Shlib.h"
+#include "APRBase.h"
+#include "APRPool.h"
+#include <apr_dso.h>
+
+namespace qpid {
+namespace sys {
+
+void Shlib::load(const char* libname) {
+ apr_dso_handle_t* aprHandle;
+ CHECK_APR_SUCCESS(
+ apr_dso_load(&aprHandle, libname, APRPool::get()));
+ handle=aprHandle;
+}
+
+void Shlib::unload() {
+ CHECK_APR_SUCCESS(
+ apr_dso_unload(static_cast<apr_dso_handle_t*>(handle)));
+}
+
+void* Shlib::getSymbol(const char* name) {
+ apr_dso_handle_sym_t symbol;
+ CHECK_APR_SUCCESS(apr_dso_sym(&symbol,
+ static_cast<apr_dso_handle_t*>(handle),
+ name));
+ return (void*) symbol;
+}
+
+}} // namespace qpid::sys
diff --git a/RC9/qpid/cpp/src/qpid/sys/apr/Socket.cpp b/RC9/qpid/cpp/src/qpid/sys/apr/Socket.cpp
new file mode 100644
index 0000000000..577268844a
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/apr/Socket.cpp
@@ -0,0 +1,114 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+
+#include "qpid/sys/Socket.h"
+
+#include "APRBase.h"
+#include "APRPool.h"
+
+#include <apr_network_io.h>
+
+namespace qpid {
+namespace sys {
+
+class SocketPrivate {
+public:
+ SocketPrivate(apr_socket_t* s = 0) :
+ socket(s)
+ {}
+
+ apr_socket_t* socket;
+};
+
+Socket::Socket() :
+ impl(new SocketPrivate)
+{
+ createTcp();
+}
+
+Socket::Socket(SocketPrivate* sp) :
+ impl(sp)
+{}
+
+Socket::~Socket() {
+ delete impl;
+}
+
+void Socket::createTcp() const {
+ apr_socket_t*& socket = impl->socket;
+ apr_socket_t* s;
+ CHECK_APR_SUCCESS(
+ apr_socket_create(
+ &s, APR_INET, SOCK_STREAM, APR_PROTO_TCP,
+ APRPool::get()));
+ socket = s;
+}
+
+void Socket::setTimeout(const Duration& interval) const {
+ apr_socket_t*& socket = impl->socket;
+ apr_socket_timeout_set(socket, interval/TIME_USEC);
+}
+
+void Socket::connect(const std::string& host, int port) const {
+ apr_socket_t*& socket = impl->socket;
+ apr_sockaddr_t* address;
+ CHECK_APR_SUCCESS(
+ apr_sockaddr_info_get(
+ &address, host.c_str(), APR_UNSPEC, port, APR_IPV4_ADDR_OK,
+ APRPool::get()));
+ CHECK_APR_SUCCESS(apr_socket_connect(socket, address));
+}
+
+void Socket::close() const {
+ apr_socket_t*& socket = impl->socket;
+ if (socket == 0) return;
+ CHECK_APR_SUCCESS(apr_socket_close(socket));
+ socket = 0;
+}
+
+ssize_t Socket::send(const void* data, size_t size) const
+{
+ apr_socket_t*& socket = impl->socket;
+ apr_size_t sent = size;
+ apr_status_t status =
+ apr_socket_send(socket, reinterpret_cast<const char*>(data), &sent);
+ if (APR_STATUS_IS_TIMEUP(status)) return SOCKET_TIMEOUT;
+ if (APR_STATUS_IS_EOF(status)) return SOCKET_EOF;
+ CHECK_APR_SUCCESS(status);
+ return sent;
+}
+
+ssize_t Socket::recv(void* data, size_t size) const
+{
+ apr_socket_t*& socket = impl->socket;
+ apr_size_t received = size;
+ apr_status_t status =
+ apr_socket_recv(socket, reinterpret_cast<char*>(data), &received);
+ if (APR_STATUS_IS_TIMEUP(status))
+ return SOCKET_TIMEOUT;
+ if (APR_STATUS_IS_EOF(status))
+ return SOCKET_EOF;
+ CHECK_APR_SUCCESS(status);
+ return received;
+}
+
+}} // namespace qpid::sys
diff --git a/RC9/qpid/cpp/src/qpid/sys/apr/Thread.cpp b/RC9/qpid/cpp/src/qpid/sys/apr/Thread.cpp
new file mode 100644
index 0000000000..3369ef7eb1
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/apr/Thread.cpp
@@ -0,0 +1,34 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Thread.h"
+#include "qpid/sys/Runnable.h"
+
+using namespace qpid::sys;
+using qpid::sys::Runnable;
+
+void* APR_THREAD_FUNC Thread::runRunnable(apr_thread_t* thread, void *data) {
+ reinterpret_cast<Runnable*>(data)->run();
+ CHECK_APR_SUCCESS(apr_thread_exit(thread, APR_SUCCESS));
+ return NULL;
+}
+
+
diff --git a/RC9/qpid/cpp/src/qpid/sys/apr/Thread.h b/RC9/qpid/cpp/src/qpid/sys/apr/Thread.h
new file mode 100644
index 0000000000..8cbbc0456e
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/apr/Thread.h
@@ -0,0 +1,106 @@
+#ifndef _sys_apr_Thread_h
+#define _sys_apr_Thread_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "APRPool.h"
+#include "APRBase.h"
+
+#include <apr_thread_proc.h>
+#include <apr_portable.h>
+
+namespace qpid {
+namespace sys {
+
+class Runnable;
+
+class Thread
+{
+ public:
+ inline static Thread current();
+
+ /** ID of current thread for logging.
+ * Workaround for broken Thread::current() in APR
+ */
+ inline static long logId();
+
+ inline static void yield();
+
+ inline Thread();
+ inline explicit Thread(qpid::sys::Runnable*);
+ inline explicit Thread(qpid::sys::Runnable&);
+
+ inline void join();
+
+ inline long id();
+
+ private:
+ static void* APR_THREAD_FUNC runRunnable(apr_thread_t* thread, void *data);
+ inline Thread(apr_thread_t* t);
+ apr_thread_t* thread;
+};
+
+Thread::Thread() : thread(0) {}
+
+Thread::Thread(Runnable* runnable) {
+ CHECK_APR_SUCCESS(
+ apr_thread_create(&thread, 0, runRunnable, runnable, APRPool::get()));
+}
+
+Thread::Thread(Runnable& runnable) {
+ CHECK_APR_SUCCESS(
+ apr_thread_create(&thread, 0, runRunnable, &runnable, APRPool::get()));
+}
+
+void Thread::join(){
+ apr_status_t status;
+ if (thread != 0)
+ CHECK_APR_SUCCESS(apr_thread_join(&status, thread));
+}
+
+long Thread::id() {
+ return long(thread);
+}
+
+/** ID of current thread for logging.
+ * Workaround for broken Thread::current() in APR
+ */
+long Thread::logId() {
+ return static_cast<long>(apr_os_thread_current());
+}
+
+Thread::Thread(apr_thread_t* t) : thread(t) {}
+
+Thread Thread::current(){
+ apr_thread_t* thr;
+ apr_os_thread_t osthr = apr_os_thread_current();
+ CHECK_APR_SUCCESS(apr_os_thread_put(&thr, &osthr, APRPool::get()));
+ return Thread(thr);
+}
+
+void Thread::yield()
+{
+ apr_thread_yield();
+}
+
+}}
+#endif /*!_sys_apr_Thread_h*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/apr/Time.cpp b/RC9/qpid/cpp/src/qpid/sys/apr/Time.cpp
new file mode 100644
index 0000000000..34e740b144
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/apr/Time.cpp
@@ -0,0 +1,36 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Time.h"
+
+#include <apr_time.h>
+
+namespace qpid {
+namespace sys {
+
+AbsTime AbsTime::now() {
+ AbsTime time_now;
+ time_now.time_ns = apr_time_now() * TIME_USEC;
+ return time_now;
+}
+
+}}
+
diff --git a/RC9/qpid/cpp/src/qpid/sys/epoll/EpollPoller.cpp b/RC9/qpid/cpp/src/qpid/sys/epoll/EpollPoller.cpp
new file mode 100644
index 0000000000..a1e624ea75
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/epoll/EpollPoller.cpp
@@ -0,0 +1,371 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Poller.h"
+#include "qpid/sys/IOHandle.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/DeletionManager.h"
+#include "qpid/sys/posix/check.h"
+#include "qpid/sys/posix/PrivatePosix.h"
+
+#include <sys/epoll.h>
+#include <errno.h>
+
+#include <assert.h>
+#include <vector>
+#include <exception>
+
+namespace qpid {
+namespace sys {
+
+// Deletion manager to handle deferring deletion of PollerHandles to when they definitely aren't being used
+DeletionManager<PollerHandlePrivate> PollerHandleDeletionManager;
+
+// Instantiate (and define) class static for DeletionManager
+template <>
+DeletionManager<PollerHandlePrivate>::AllThreadsStatuses DeletionManager<PollerHandlePrivate>::allThreadsStatuses(0);
+
+class PollerHandlePrivate {
+ friend class Poller;
+ friend class PollerHandle;
+
+ enum FDStat {
+ ABSENT,
+ MONITORED,
+ INACTIVE,
+ HUNGUP,
+ MONITORED_HUNGUP,
+ DELETED
+ };
+
+ int fd;
+ ::__uint32_t events;
+ PollerHandle* pollerHandle;
+ FDStat stat;
+ Mutex lock;
+
+ PollerHandlePrivate(int f, PollerHandle* p) :
+ fd(f),
+ events(0),
+ pollerHandle(p),
+ stat(ABSENT) {
+ }
+
+ bool isActive() const {
+ return stat == MONITORED || stat == MONITORED_HUNGUP;
+ }
+
+ void setActive() {
+ stat = (stat == HUNGUP) ? MONITORED_HUNGUP : MONITORED;
+ }
+
+ bool isInactive() const {
+ return stat == INACTIVE || stat == HUNGUP;
+ }
+
+ void setInactive() {
+ stat = INACTIVE;
+ }
+
+ bool isIdle() const {
+ return stat == ABSENT;
+ }
+
+ void setIdle() {
+ stat = ABSENT;
+ }
+
+ bool isHungup() const {
+ return stat == MONITORED_HUNGUP || stat == HUNGUP;
+ }
+
+ void setHungup() {
+ assert(stat == MONITORED);
+ stat = HUNGUP;
+ }
+
+ bool isDeleted() const {
+ return stat == DELETED;
+ }
+
+ void setDeleted() {
+ stat = DELETED;
+ }
+};
+
+PollerHandle::PollerHandle(const IOHandle& h) :
+ impl(new PollerHandlePrivate(toFd(h.impl), this))
+{}
+
+PollerHandle::~PollerHandle() {
+ {
+ ScopedLock<Mutex> l(impl->lock);
+ if (impl->isDeleted()) {
+ return;
+ }
+ if (impl->isActive()) {
+ impl->setDeleted();
+ }
+ }
+ PollerHandleDeletionManager.markForDeletion(impl);
+}
+
+/**
+ * Concrete implementation of Poller to use the Linux specific epoll
+ * interface
+ */
+class PollerPrivate {
+ friend class Poller;
+
+ static const int DefaultFds = 256;
+
+ struct ReadablePipe {
+ int fds[2];
+
+ /**
+ * This encapsulates an always readable pipe which we can add
+ * to the epoll set to force epoll_wait to return
+ */
+ ReadablePipe() {
+ QPID_POSIX_CHECK(::pipe(fds));
+ // Just write the pipe's fds to the pipe
+ QPID_POSIX_CHECK(::write(fds[1], fds, 2));
+ }
+
+ ~ReadablePipe() {
+ ::close(fds[0]);
+ ::close(fds[1]);
+ }
+
+ int getFD() {
+ return fds[0];
+ }
+ };
+
+ static ReadablePipe alwaysReadable;
+
+ const int epollFd;
+ bool isShutdown;
+
+ static ::__uint32_t directionToEpollEvent(Poller::Direction dir) {
+ switch (dir) {
+ case Poller::INPUT: return ::EPOLLIN;
+ case Poller::OUTPUT: return ::EPOLLOUT;
+ case Poller::INOUT: return ::EPOLLIN | ::EPOLLOUT;
+ default: return 0;
+ }
+ }
+
+ static Poller::EventType epollToDirection(::__uint32_t events) {
+ // POLLOUT & POLLHUP are mutually exclusive really, but at least socketpairs
+ // can give you both!
+ events = (events & ::EPOLLHUP) ? events & ~::EPOLLOUT : events;
+ ::__uint32_t e = events & (::EPOLLIN | ::EPOLLOUT);
+ switch (e) {
+ case ::EPOLLIN: return Poller::READABLE;
+ case ::EPOLLOUT: return Poller::WRITABLE;
+ case ::EPOLLIN | ::EPOLLOUT: return Poller::READ_WRITABLE;
+ default:
+ return (events & (::EPOLLHUP | ::EPOLLERR)) ?
+ Poller::DISCONNECTED : Poller::INVALID;
+ }
+ }
+
+ PollerPrivate() :
+ epollFd(::epoll_create(DefaultFds)),
+ isShutdown(false) {
+ QPID_POSIX_CHECK(epollFd);
+ }
+
+ ~PollerPrivate() {
+ // It's probably okay to ignore any errors here as there can't be data loss
+ ::close(epollFd);
+ }
+};
+
+PollerPrivate::ReadablePipe PollerPrivate::alwaysReadable;
+
+void Poller::addFd(PollerHandle& handle, Direction dir) {
+ PollerHandlePrivate& eh = *handle.impl;
+ ScopedLock<Mutex> l(eh.lock);
+ ::epoll_event epe;
+ int op;
+
+ if (eh.isIdle()) {
+ op = EPOLL_CTL_ADD;
+ epe.events = PollerPrivate::directionToEpollEvent(dir) | ::EPOLLONESHOT;
+ } else {
+ assert(eh.isActive());
+ op = EPOLL_CTL_MOD;
+ epe.events = eh.events | PollerPrivate::directionToEpollEvent(dir);
+ }
+ epe.data.u64 = 0; // Keep valgrind happy
+ epe.data.ptr = &eh;
+
+ QPID_POSIX_CHECK(::epoll_ctl(impl->epollFd, op, eh.fd, &epe));
+
+ // Record monitoring state of this fd
+ eh.events = epe.events;
+ eh.setActive();
+}
+
+void Poller::delFd(PollerHandle& handle) {
+ PollerHandlePrivate& eh = *handle.impl;
+ ScopedLock<Mutex> l(eh.lock);
+ assert(!eh.isIdle());
+ int rc = ::epoll_ctl(impl->epollFd, EPOLL_CTL_DEL, eh.fd, 0);
+ // Ignore EBADF since deleting a nonexistent fd has the overall required result!
+ // And allows the case where a sloppy program closes the fd and then does the delFd()
+ if (rc == -1 && errno != EBADF) {
+ QPID_POSIX_CHECK(rc);
+ }
+ eh.setIdle();
+}
+
+// modFd is equivalent to delFd followed by addFd
+void Poller::modFd(PollerHandle& handle, Direction dir) {
+ PollerHandlePrivate& eh = *handle.impl;
+ ScopedLock<Mutex> l(eh.lock);
+ assert(!eh.isIdle());
+
+ ::epoll_event epe;
+ epe.events = PollerPrivate::directionToEpollEvent(dir) | ::EPOLLONESHOT;
+ epe.data.u64 = 0; // Keep valgrind happy
+ epe.data.ptr = &eh;
+
+ QPID_POSIX_CHECK(::epoll_ctl(impl->epollFd, EPOLL_CTL_MOD, eh.fd, &epe));
+
+ // Record monitoring state of this fd
+ eh.events = epe.events;
+ eh.setActive();
+}
+
+void Poller::rearmFd(PollerHandle& handle) {
+ PollerHandlePrivate& eh = *handle.impl;
+ ScopedLock<Mutex> l(eh.lock);
+ assert(eh.isInactive());
+
+ ::epoll_event epe;
+ epe.events = eh.events;
+ epe.data.u64 = 0; // Keep valgrind happy
+ epe.data.ptr = &eh;
+
+ QPID_POSIX_CHECK(::epoll_ctl(impl->epollFd, EPOLL_CTL_MOD, eh.fd, &epe));
+
+ eh.setActive();
+}
+
+void Poller::shutdown() {
+ // NB: this function must be async-signal safe, it must not
+ // call any function that is not async-signal safe.
+
+ // Allow sloppy code to shut us down more than once
+ if (impl->isShutdown)
+ return;
+
+ // Don't use any locking here - isshutdown will be visible to all
+ // after the epoll_ctl() anyway (it's a memory barrier)
+ impl->isShutdown = true;
+
+ // Add always readable fd to epoll (not EPOLLONESHOT)
+ int fd = impl->alwaysReadable.getFD();
+ ::epoll_event epe;
+ epe.events = ::EPOLLIN;
+ epe.data.u64 = 0; // Keep valgrind happy - don't strictly need next line now
+ epe.data.ptr = 0;
+ QPID_POSIX_CHECK(::epoll_ctl(impl->epollFd, EPOLL_CTL_ADD, fd, &epe));
+}
+
+Poller::Event Poller::wait(Duration timeout) {
+ epoll_event epe;
+ int timeoutMs = (timeout == TIME_INFINITE) ? -1 : timeout / TIME_MSEC;
+
+ // Repeat until we weren't interupted
+ do {
+ PollerHandleDeletionManager.markAllUnusedInThisThread();
+ int rc = ::epoll_wait(impl->epollFd, &epe, 1, timeoutMs);
+
+ if (impl->isShutdown) {
+ PollerHandleDeletionManager.markAllUnusedInThisThread();
+ return Event(0, SHUTDOWN);
+ }
+
+ if (rc ==-1 && errno != EINTR) {
+ QPID_POSIX_CHECK(rc);
+ } else if (rc > 0) {
+ assert(rc == 1);
+ PollerHandlePrivate& eh = *static_cast<PollerHandlePrivate*>(epe.data.ptr);
+
+ ScopedLock<Mutex> l(eh.lock);
+
+ // the handle could have gone inactive since we left the epoll_wait
+ if (eh.isActive()) {
+ PollerHandle* handle = eh.pollerHandle;
+
+ // If the connection has been hungup we could still be readable
+ // (just not writable), allow us to readable until we get here again
+ if (epe.events & ::EPOLLHUP) {
+ if (eh.isHungup()) {
+ return Event(handle, DISCONNECTED);
+ }
+ eh.setHungup();
+ } else {
+ eh.setInactive();
+ }
+ return Event(handle, PollerPrivate::epollToDirection(epe.events));
+ } else if (eh.isDeleted()) {
+ // The handle has been deleted whilst still active and so must be removed
+ // from the poller
+ int rc = ::epoll_ctl(impl->epollFd, EPOLL_CTL_DEL, eh.fd, 0);
+ // Ignore EBADF since it's quite likely that we could race with closing the fd
+ if (rc == -1 && errno != EBADF) {
+ QPID_POSIX_CHECK(rc);
+ }
+ }
+ }
+ // We only get here if one of the following:
+ // * epoll_wait was interrupted by a signal
+ // * epoll_wait timed out
+ // * the state of the handle changed after being returned by epoll_wait
+ //
+ // The only things we can do here are return a timeout or wait more.
+ // Obviously if we timed out we return timeout; if the wait was meant to
+ // be indefinite then we should never return with a time out so we go again.
+ // If the wait wasn't indefinite, but we were interrupted then we have to return
+ // with a timeout as we don't know how long we've waited so far and so we can't
+ // continue the wait.
+ if (rc == 0 || timeoutMs != -1) {
+ PollerHandleDeletionManager.markAllUnusedInThisThread();
+ return Event(0, TIMEOUT);
+ }
+ } while (true);
+}
+
+// Concrete constructors
+Poller::Poller() :
+ impl(new PollerPrivate())
+{}
+
+Poller::~Poller() {
+ delete impl;
+}
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp b/RC9/qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp
new file mode 100644
index 0000000000..9a5798311b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp
@@ -0,0 +1,595 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/AsynchIO.h"
+#include "qpid/sys/Socket.h"
+#include "qpid/sys/Time.h"
+#include "qpid/log/Statement.h"
+
+#include "check.h"
+
+// TODO The basic algorithm here is not really POSIX specific and with a
+// bit more abstraction could (should) be promoted to be platform portable
+#include <unistd.h>
+#include <sys/socket.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+
+#include <boost/bind.hpp>
+
+using namespace qpid::sys;
+
+namespace {
+
+struct StaticInit {
+ StaticInit() {
+ /**
+ * Make *process* not generate SIGPIPE when writing to closed
+ * pipe/socket (necessary as default action is to terminate process)
+ */
+ ::signal(SIGPIPE, SIG_IGN);
+ };
+} init;
+
+/*
+ * We keep per thread state to avoid locking overhead. The assumption is that
+ * on average all the connections are serviced by all the threads so the state
+ * recorded in each thread is about the same. If this turns out not to be the
+ * case we could rebalance the info occasionally.
+ */
+__thread int threadReadTotal = 0;
+__thread int threadMaxRead = 0;
+__thread int threadReadCount = 0;
+__thread int threadWriteTotal = 0;
+__thread int threadWriteCount = 0;
+__thread int64_t threadMaxReadTimeNs = 2 * 1000000; // start at 2ms
+}
+
+/*
+ * Asynch Acceptor
+ */
+namespace qpid {
+namespace sys {
+
+class AsynchAcceptorPrivate {
+public:
+ AsynchAcceptorPrivate(const Socket& s, AsynchAcceptor::Callback callback);
+ void start(Poller::shared_ptr poller);
+
+private:
+ void readable(DispatchHandle& handle);
+
+private:
+ AsynchAcceptor::Callback acceptedCallback;
+ DispatchHandle handle;
+ const Socket& socket;
+
+};
+
+}} // namespace qpid::sys
+
+AsynchAcceptor::AsynchAcceptor(const Socket& s, Callback callback) :
+ impl(new AsynchAcceptorPrivate(s, callback))
+{}
+
+AsynchAcceptor::~AsynchAcceptor()
+{ delete impl;}
+
+void AsynchAcceptor::start(Poller::shared_ptr poller) {
+ impl->start(poller);
+}
+
+AsynchAcceptorPrivate::AsynchAcceptorPrivate(const Socket& s,
+ AsynchAcceptor::Callback callback) :
+ acceptedCallback(callback),
+ handle(s, boost::bind(&AsynchAcceptorPrivate::readable, this, _1), 0, 0),
+ socket(s) {
+
+ s.setNonblocking();
+}
+
+void AsynchAcceptorPrivate::start(Poller::shared_ptr poller) {
+ handle.startWatch(poller);
+}
+
+/*
+ * We keep on accepting as long as there is something to accept
+ */
+void AsynchAcceptorPrivate::readable(DispatchHandle& h) {
+ Socket* s;
+ do {
+ errno = 0;
+ // TODO: Currently we ignore the peers address, perhaps we should
+ // log it or use it for connection acceptance.
+ try {
+ s = socket.accept(0, 0);
+ if (s) {
+ acceptedCallback(*s);
+ } else {
+ break;
+ }
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Could not accept socket: " << e.what());
+ }
+ } while (true);
+
+ h.rewatch();
+}
+
+/*
+ * Asynch Connector
+ */
+namespace qpid {
+namespace sys {
+namespace posix {
+
+/*
+ * POSIX version of AsynchIO TCP socket connector.
+ *
+ * The class is implemented in terms of DispatchHandle to allow it to be
+ * deleted by deleting the contained DispatchHandle.
+ */
+class AsynchConnector : public qpid::sys::AsynchConnector,
+ private DispatchHandle {
+
+private:
+ void connComplete(DispatchHandle& handle);
+ void failure(int, std::string);
+
+private:
+ ConnectedCallback connCallback;
+ FailedCallback failCallback;
+ const Socket& socket;
+
+public:
+ AsynchConnector(const Socket& socket,
+ Poller::shared_ptr poller,
+ std::string hostname,
+ uint16_t port,
+ ConnectedCallback connCb,
+ FailedCallback failCb = 0);
+};
+
+AsynchConnector::AsynchConnector(const Socket& s,
+ Poller::shared_ptr poller,
+ std::string hostname,
+ uint16_t port,
+ ConnectedCallback connCb,
+ FailedCallback failCb) :
+ DispatchHandle(s,
+ 0,
+ boost::bind(&AsynchConnector::connComplete, this, _1),
+ boost::bind(&AsynchConnector::connComplete, this, _1)),
+ connCallback(connCb),
+ failCallback(failCb),
+ socket(s)
+{
+ socket.setNonblocking();
+ try {
+ socket.connect(hostname, port);
+ startWatch(poller);
+ } catch(std::exception& e) {
+ failure(-1, std::string(e.what()));
+ }
+}
+
+void AsynchConnector::connComplete(DispatchHandle& h)
+{
+ int errCode = socket.getError();
+
+ h.stopWatch();
+ if (errCode == 0) {
+ connCallback(socket);
+ DispatchHandle::doDelete();
+ } else {
+ // TODO: This need to be fixed as strerror isn't thread safe
+ failure(errCode, std::string(::strerror(errCode)));
+ }
+}
+
+void AsynchConnector::failure(int errCode, std::string message)
+{
+ if (failCallback)
+ failCallback(errCode, message);
+
+ socket.close();
+ delete &socket;
+
+ DispatchHandle::doDelete();
+}
+
+} // namespace posix
+
+
+AsynchConnector* qpid::sys::AsynchConnector::create(const Socket& s,
+ Poller::shared_ptr poller,
+ std::string hostname,
+ uint16_t port,
+ ConnectedCallback connCb,
+ FailedCallback failCb)
+{
+ return new qpid::sys::posix::AsynchConnector(s,
+ poller,
+ hostname,
+ port,
+ connCb,
+ failCb);
+}
+
+/*
+ * POSIX version of AsynchIO reader/writer
+ *
+ * The class is implemented in terms of DispatchHandle to allow it to be
+ * deleted by deleting the contained DispatchHandle.
+ */
+namespace posix {
+
+class AsynchIO : public qpid::sys::AsynchIO, private DispatchHandle {
+
+public:
+ AsynchIO(const Socket& s,
+ ReadCallback rCb,
+ EofCallback eofCb,
+ DisconnectCallback disCb,
+ ClosedCallback cCb = 0,
+ BuffersEmptyCallback eCb = 0,
+ IdleCallback iCb = 0);
+
+ // Methods inherited from qpid::sys::AsynchIO
+
+ virtual void queueForDeletion();
+
+ virtual void start(Poller::shared_ptr poller);
+ virtual void queueReadBuffer(BufferBase* buff);
+ virtual void unread(BufferBase* buff);
+ virtual void queueWrite(BufferBase* buff);
+ virtual void notifyPendingWrite();
+ virtual void queueWriteClose();
+ virtual bool writeQueueEmpty();
+ virtual void startReading();
+ virtual BufferBase* getQueuedBuffer();
+
+private:
+ ~AsynchIO();
+
+ // Methods that are callback targets from Dispatcher.
+ void readable(DispatchHandle& handle);
+ void writeable(DispatchHandle& handle);
+ void disconnected(DispatchHandle& handle);
+ void close(DispatchHandle& handle);
+
+private:
+ ReadCallback readCallback;
+ EofCallback eofCallback;
+ DisconnectCallback disCallback;
+ ClosedCallback closedCallback;
+ BuffersEmptyCallback emptyCallback;
+ IdleCallback idleCallback;
+ const Socket& socket;
+ std::deque<BufferBase*> bufferQueue;
+ std::deque<BufferBase*> writeQueue;
+ bool queuedClose;
+ /**
+ * This flag is used to detect and handle concurrency between
+ * calls to notifyPendingWrite() (which can be made from any thread) and
+ * the execution of the writeable() method (which is always on the
+ * thread processing this handle.
+ */
+ volatile bool writePending;
+};
+
+AsynchIO::AsynchIO(const Socket& s,
+ ReadCallback rCb, EofCallback eofCb, DisconnectCallback disCb,
+ ClosedCallback cCb, BuffersEmptyCallback eCb, IdleCallback iCb) :
+
+ DispatchHandle(s,
+ boost::bind(&AsynchIO::readable, this, _1),
+ boost::bind(&AsynchIO::writeable, this, _1),
+ boost::bind(&AsynchIO::disconnected, this, _1)),
+ readCallback(rCb),
+ eofCallback(eofCb),
+ disCallback(disCb),
+ closedCallback(cCb),
+ emptyCallback(eCb),
+ idleCallback(iCb),
+ socket(s),
+ queuedClose(false),
+ writePending(false) {
+
+ s.setNonblocking();
+}
+
+struct deleter
+{
+ template <typename T>
+ void operator()(T *ptr){ delete ptr;}
+};
+
+AsynchIO::~AsynchIO() {
+ std::for_each( bufferQueue.begin(), bufferQueue.end(), deleter());
+ std::for_each( writeQueue.begin(), writeQueue.end(), deleter());
+}
+
+void AsynchIO::queueForDeletion() {
+ DispatchHandle::doDelete();
+}
+
+void AsynchIO::start(Poller::shared_ptr poller) {
+ DispatchHandle::startWatch(poller);
+}
+
+void AsynchIO::queueReadBuffer(BufferBase* buff) {
+ assert(buff);
+ buff->dataStart = 0;
+ buff->dataCount = 0;
+ bufferQueue.push_back(buff);
+ DispatchHandle::rewatchRead();
+}
+
+void AsynchIO::unread(BufferBase* buff) {
+ assert(buff);
+ if (buff->dataStart != 0) {
+ memmove(buff->bytes, buff->bytes+buff->dataStart, buff->dataCount);
+ buff->dataStart = 0;
+ }
+ bufferQueue.push_front(buff);
+ DispatchHandle::rewatchRead();
+}
+
+void AsynchIO::queueWrite(BufferBase* buff) {
+ assert(buff);
+ // If we've already closed the socket then throw the write away
+ if (queuedClose) {
+ bufferQueue.push_front(buff);
+ return;
+ } else {
+ writeQueue.push_front(buff);
+ }
+ writePending = false;
+ DispatchHandle::rewatchWrite();
+}
+
+void AsynchIO::notifyPendingWrite() {
+ writePending = true;
+ DispatchHandle::rewatchWrite();
+}
+
+void AsynchIO::queueWriteClose() {
+ queuedClose = true;
+ DispatchHandle::rewatchWrite();
+}
+
+bool AsynchIO::writeQueueEmpty() {
+ return writeQueue.empty();
+}
+
+void AsynchIO::startReading() {
+ DispatchHandle::rewatchRead();
+}
+
+/** Return a queued buffer if there are enough
+ * to spare
+ */
+AsynchIO::BufferBase* AsynchIO::getQueuedBuffer() {
+ // Always keep at least one buffer (it might have data that was "unread" in it)
+ if (bufferQueue.size()<=1)
+ return 0;
+ BufferBase* buff = bufferQueue.back();
+ assert(buff);
+ buff->dataStart = 0;
+ buff->dataCount = 0;
+ bufferQueue.pop_back();
+ return buff;
+}
+
+/*
+ * We keep on reading as long as we have something to read and a buffer to put
+ * it in
+ */
+void AsynchIO::readable(DispatchHandle& h) {
+ int readTotal = 0;
+ AbsTime readStartTime = AbsTime::now();
+ do {
+ // (Try to) get a buffer
+ if (!bufferQueue.empty()) {
+ // Read into buffer
+ BufferBase* buff = bufferQueue.front();
+ assert(buff);
+ bufferQueue.pop_front();
+ errno = 0;
+ int readCount = buff->byteCount-buff->dataCount;
+ int rc = socket.read(buff->bytes + buff->dataCount, readCount);
+ if (rc > 0) {
+ buff->dataCount += rc;
+ threadReadTotal += rc;
+ readTotal += rc;
+
+ if (!readCallback(*this, buff)) {
+ // We were told to flow control reading at this point
+ h.unwatchRead();
+ break;
+ }
+
+ if (rc != readCount) {
+ // If we didn't fill the read buffer then time to stop reading
+ break;
+ }
+
+ // Stop reading if we've overrun our timeslot
+ if (Duration(readStartTime, AbsTime::now()) > threadMaxReadTimeNs) {
+ break;
+ }
+
+ } else {
+ // Put buffer back (at front so it doesn't interfere with unread buffers)
+ bufferQueue.push_front(buff);
+ assert(buff);
+
+ // Eof or other side has gone away
+ if (rc == 0 || errno == ECONNRESET) {
+ eofCallback(*this);
+ h.unwatchRead();
+ break;
+ } else if (errno == EAGAIN) {
+ // We have just put a buffer back so we know
+ // we can carry on watching for reads
+ break;
+ } else {
+ // Report error then just treat as a socket disconnect
+ QPID_LOG(error, "Error reading socket: " << qpid::sys::strError(rc) << "(" << rc << ")" );
+ eofCallback(*this);
+ h.unwatchRead();
+ break;
+ }
+ }
+ } else {
+ // Something to read but no buffer
+ if (emptyCallback) {
+ emptyCallback(*this);
+ }
+ // If we still have no buffers we can't do anything more
+ if (bufferQueue.empty()) {
+ h.unwatchRead();
+ break;
+ }
+
+ }
+ } while (true);
+
+ ++threadReadCount;
+ threadMaxRead = std::max(threadMaxRead, readTotal);
+ return;
+}
+
+/*
+ * We carry on writing whilst we have data to write and we can write
+ */
+void AsynchIO::writeable(DispatchHandle& h) {
+ int writeTotal = 0;
+ do {
+ // See if we've got something to write
+ if (!writeQueue.empty()) {
+ // Write buffer
+ BufferBase* buff = writeQueue.back();
+ writeQueue.pop_back();
+ errno = 0;
+ assert(buff->dataStart+buff->dataCount <= buff->byteCount);
+ int rc = socket.write(buff->bytes+buff->dataStart, buff->dataCount);
+ if (rc >= 0) {
+ threadWriteTotal += rc;
+ writeTotal += rc;
+
+ // If we didn't write full buffer put rest back
+ if (rc != buff->dataCount) {
+ buff->dataStart += rc;
+ buff->dataCount -= rc;
+ writeQueue.push_back(buff);
+ break;
+ }
+
+ // Recycle the buffer
+ queueReadBuffer(buff);
+
+ // If we've already written more than the max for reading then stop
+ // (this is to stop writes dominating reads)
+ if (writeTotal > threadMaxRead)
+ break;
+ } else {
+ // Put buffer back
+ writeQueue.push_back(buff);
+ if (errno == ECONNRESET || errno == EPIPE) {
+ // Just stop watching for write here - we'll get a
+ // disconnect callback soon enough
+ h.unwatchWrite();
+ break;
+ } else if (errno == EAGAIN) {
+ // We have just put a buffer back so we know
+ // we can carry on watching for writes
+ break;
+ } else {
+ QPID_POSIX_CHECK(rc);
+ }
+ }
+ } else {
+ // If we're waiting to close the socket then can do it now as there is nothing to write
+ if (queuedClose) {
+ close(h);
+ break;
+ }
+ // Fd is writable, but nothing to write
+ if (idleCallback) {
+ writePending = false;
+ idleCallback(*this);
+ }
+ // If we still have no buffers to write we can't do anything more
+ if (writeQueue.empty() && !writePending && !queuedClose) {
+ h.unwatchWrite();
+ // The following handles the case where writePending is
+ // set to true after the test above; in this case its
+ // possible that the unwatchWrite overwrites the
+ // desired rewatchWrite so we correct that here
+ if (writePending)
+ h.rewatchWrite();
+ break;
+ }
+ }
+ } while (true);
+
+ ++threadWriteCount;
+ return;
+}
+
+void AsynchIO::disconnected(DispatchHandle& h) {
+ // If we've already queued close do it instead of disconnected callback
+ if (queuedClose) {
+ close(h);
+ } else if (disCallback) {
+ disCallback(*this);
+ h.unwatch();
+ }
+}
+
+/*
+ * Close the socket and callback to say we've done it
+ */
+void AsynchIO::close(DispatchHandle& h) {
+ h.stopWatch();
+ socket.close();
+ if (closedCallback) {
+ closedCallback(*this, socket);
+ }
+}
+
+} // namespace posix
+
+AsynchIO* qpid::sys::AsynchIO::create(const Socket& s,
+ AsynchIO::ReadCallback rCb,
+ AsynchIO::EofCallback eofCb,
+ AsynchIO::DisconnectCallback disCb,
+ AsynchIO::ClosedCallback cCb,
+ AsynchIO::BuffersEmptyCallback eCb,
+ AsynchIO::IdleCallback iCb)
+{
+ return new qpid::sys::posix::AsynchIO(s, rCb, eofCb, disCb, cCb, eCb, iCb);
+}
+
+}} // namespace qpid::sys
diff --git a/RC9/qpid/cpp/src/qpid/sys/posix/Condition.h b/RC9/qpid/cpp/src/qpid/sys/posix/Condition.h
new file mode 100644
index 0000000000..86d6500ee9
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/posix/Condition.h
@@ -0,0 +1,86 @@
+#ifndef _sys_posix_Condition_h
+#define _sys_posix_Condition_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "PrivatePosix.h"
+
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Time.h"
+
+#include <time.h>
+#include <sys/errno.h>
+#include <boost/noncopyable.hpp>
+
+namespace qpid {
+namespace sys {
+
+/**
+ * A condition variable for thread synchronization.
+ */
+class Condition
+{
+ public:
+ inline Condition();
+ inline ~Condition();
+ inline void wait(Mutex&);
+ inline bool wait(Mutex&, const AbsTime& absoluteTime);
+ inline void notify();
+ inline void notifyAll();
+
+ private:
+ pthread_cond_t condition;
+};
+
+Condition::Condition() {
+ QPID_POSIX_ASSERT_THROW_IF(pthread_cond_init(&condition, 0));
+}
+
+Condition::~Condition() {
+ QPID_POSIX_ASSERT_THROW_IF(pthread_cond_destroy(&condition));
+}
+
+void Condition::wait(Mutex& mutex) {
+ QPID_POSIX_ASSERT_THROW_IF(pthread_cond_wait(&condition, &mutex.mutex));
+}
+
+bool Condition::wait(Mutex& mutex, const AbsTime& absoluteTime){
+ struct timespec ts;
+ toTimespec(ts, Duration(absoluteTime));
+ int status = pthread_cond_timedwait(&condition, &mutex.mutex, &ts);
+ if (status != 0) {
+ if (status == ETIMEDOUT) return false;
+ throw QPID_POSIX_ERROR(status);
+ }
+ return true;
+}
+
+void Condition::notify(){
+ QPID_POSIX_ASSERT_THROW_IF(pthread_cond_signal(&condition));
+}
+
+void Condition::notifyAll(){
+ QPID_POSIX_ASSERT_THROW_IF(pthread_cond_broadcast(&condition));
+}
+
+}}
+#endif /*!_sys_posix_Condition_h*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/posix/FileSysDir.cpp b/RC9/qpid/cpp/src/qpid/sys/posix/FileSysDir.cpp
new file mode 100755
index 0000000000..22dc487e74
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/posix/FileSysDir.cpp
@@ -0,0 +1,54 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/sys/FileSysDir.h"
+#include "qpid/sys/StrError.h"
+#include "qpid/Exception.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <cerrno>
+#include <unistd.h>
+
+namespace qpid {
+namespace sys {
+
+bool FileSysDir::exists (void) const
+{
+ const char *cpath = dirPath.c_str ();
+ struct stat s;
+ if (::stat(cpath, &s)) {
+ if (errno == ENOENT) {
+ return false;
+ }
+ throw qpid::Exception (strError(errno) +
+ ": Can't check directory: " + dirPath);
+ }
+ if (S_ISDIR(s.st_mode))
+ return true;
+ throw qpid::Exception(dirPath + " is not a directory");
+}
+
+void FileSysDir::mkdir(void)
+{
+ if (::mkdir(dirPath.c_str(), 0755))
+ throw Exception ("Can't create directory: " + dirPath);
+}
+
+}} // namespace qpid::sys
diff --git a/RC9/qpid/cpp/src/qpid/sys/posix/Fork.cpp b/RC9/qpid/cpp/src/qpid/sys/posix/Fork.cpp
new file mode 100644
index 0000000000..ec3af620ef
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/posix/Fork.cpp
@@ -0,0 +1,127 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "qpid/sys/Fork.h"
+#include "qpid/log/Statement.h"
+#include "qpid/Exception.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace qpid {
+namespace sys {
+
+using namespace std;
+
+namespace {
+
+void writeStr(int fd, const std::string& str) {
+ const char* WRITE_ERR = "Error writing to parent process";
+ int size = str.size();
+ if (int(sizeof(size)) > ::write(fd, &size, sizeof(size))) throw ErrnoException(WRITE_ERR);
+ if (size > ::write(fd, str.data(), size)) throw ErrnoException(WRITE_ERR);
+}
+
+string readStr(int fd) {
+ string value;
+ const char* READ_ERR = "Error reading from forked process";
+ int size;
+ if (int(sizeof(size)) > ::read(fd, &size, sizeof(size))) throw ErrnoException(READ_ERR);
+ if (size > 0) { // Read string message
+ value.resize(size);
+ if (size > ::read(fd, const_cast<char*>(value.data()), size)) throw ErrnoException(READ_ERR);
+ }
+ return value;
+}
+
+} // namespace
+
+Fork::Fork() {}
+Fork::~Fork() {}
+
+void Fork::fork() {
+ pid_t pid = ::fork();
+ if (pid < 0) throw ErrnoException("Failed to fork the process");
+ if (pid == 0) child();
+ else parent(pid);
+}
+
+ForkWithMessage::ForkWithMessage() {
+ pipeFds[0] = pipeFds[1] = -1;
+}
+
+struct AutoCloseFd {
+ int fd;
+ AutoCloseFd(int d) : fd(d) {}
+ ~AutoCloseFd() { ::close(fd); }
+};
+
+void ForkWithMessage::fork() {
+ if(::pipe(pipeFds) < 0) throw ErrnoException("Can't create pipe");
+ pid_t pid = ::fork();
+ if(pid < 0) throw ErrnoException("Fork fork failed");
+ if (pid == 0) { // Child
+ AutoCloseFd ac(pipeFds[1]); // Write side.
+ ::close(pipeFds[0]); // Read side
+ try {
+ child();
+ }
+ catch (const std::exception& e) {
+ QPID_LOG(error, "Error in forked child: " << e.what());
+ std::string msg = e.what();
+ if (msg.empty()) msg = " "; // Make sure we send a non-empty error string.
+ writeStr(pipeFds[1], msg);
+ }
+ }
+ else { // Parent
+ close(pipeFds[1]); // Write side.
+ AutoCloseFd ac(pipeFds[0]); // Read side
+ parent(pid);
+ }
+}
+
+string ForkWithMessage::wait(int timeout) { // parent waits for child.
+ errno = 0;
+ struct timeval tv;
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(pipeFds[0], &fds);
+ int n=select(FD_SETSIZE, &fds, 0, 0, &tv);
+ if(n<0) throw ErrnoException("Error waiting for fork");
+ if (n==0) throw Exception("Timed out waiting for fork");
+
+ string error = readStr(pipeFds[0]);
+ if (error.empty()) return readStr(pipeFds[0]);
+ else throw Exception("Error in forked process: " + error);
+}
+
+// Write empty error string followed by value string to pipe.
+void ForkWithMessage::ready(const string& value) { // child
+ // Write empty string for error followed by value.
+ writeStr(pipeFds[1], string()); // No error
+ writeStr(pipeFds[1], value);
+}
+
+
+}} // namespace qpid::sys
diff --git a/RC9/qpid/cpp/src/qpid/sys/posix/Fork.h b/RC9/qpid/cpp/src/qpid/sys/posix/Fork.h
new file mode 100644
index 0000000000..698c61ed30
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/posix/Fork.h
@@ -0,0 +1,82 @@
+#ifndef QPID_SYS_POSIX_FORK_H
+#define QPID_SYS_POSIX_FORK_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <string>
+#include <sys/types.h>
+
+namespace qpid {
+namespace sys {
+
+/**
+ * Fork the process. Call parent() in parent and child() in child.
+ */
+class Fork {
+ public:
+ Fork();
+ virtual ~Fork();
+
+ /**
+ * Fork the process.
+ * Calls parent() in the parent process, child() in the child.
+ */
+ virtual void fork();
+
+ protected:
+
+ /** Called in parent process.
+ *@child pid of child process
+ */
+ virtual void parent(pid_t child) = 0;
+
+ /** Called in child process */
+ virtual void child() = 0;
+};
+
+/**
+ * Like Fork but also allows the child to send a string message
+ * or throw an exception to the parent.
+ */
+class ForkWithMessage : public Fork {
+ public:
+ ForkWithMessage();
+ void fork();
+
+ protected:
+ /** Call from parent(): wait for child to send a value or throw exception.
+ * @timeout in seconds to wait for response.
+ * @return value passed by child to ready().
+ */
+ std::string wait(int timeout);
+
+ /** Call from child(): Send a value to the parent.
+ *@param value returned by parent call to wait().
+ */
+ void ready(const std::string& value);
+
+ private:
+ int pipeFds[2];
+};
+
+}} // namespace qpid::sys
+
+
+
+#endif /*!QPID_SYS_POSIX_FORK_H*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/posix/IOHandle.cpp b/RC9/qpid/cpp/src/qpid/sys/posix/IOHandle.cpp
new file mode 100644
index 0000000000..80b487eadc
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/posix/IOHandle.cpp
@@ -0,0 +1,42 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/IOHandle.h"
+
+#include "PrivatePosix.h"
+
+namespace qpid {
+namespace sys {
+
+int toFd(const IOHandlePrivate* h)
+{
+ return h->fd;
+}
+
+IOHandle::IOHandle(IOHandlePrivate* h) :
+ impl(h)
+{}
+
+IOHandle::~IOHandle() {
+ delete impl;
+}
+
+}} // namespace qpid::sys
diff --git a/RC9/qpid/cpp/src/qpid/sys/posix/IntegerTypes.h b/RC9/qpid/cpp/src/qpid/sys/posix/IntegerTypes.h
new file mode 100755
index 0000000000..ce97f7bde8
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/posix/IntegerTypes.h
@@ -0,0 +1,26 @@
+#ifndef QPID_SYS_POSIX_INTEGERTYPES_H
+#define QPID_SYS_POSIX_INTEGERTYPES_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <stdint.h>
+
+#endif /*!QPID_SYS_INTEGERTYPES_H*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/posix/LockFile.cpp b/RC9/qpid/cpp/src/qpid/sys/posix/LockFile.cpp
new file mode 100755
index 0000000000..af9ecd7d66
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/posix/LockFile.cpp
@@ -0,0 +1,89 @@
+/*
+ *
+ * Copyright (c) 2008 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/sys/LockFile.h"
+
+#include <string>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "check.h"
+
+namespace qpid {
+namespace sys {
+
+class LockFilePrivate {
+ friend class LockFile;
+
+ int fd;
+
+public:
+ LockFilePrivate(int f) : fd(f) {}
+};
+
+LockFile::LockFile(const std::string& path_, bool create)
+ : path(path_), created(create) {
+
+ errno = 0;
+ int flags=create ? O_WRONLY|O_CREAT|O_NOFOLLOW : O_RDWR;
+ int fd = ::open(path.c_str(), flags, 0644);
+ if (fd < 0) throw ErrnoException("Cannot open " + path, errno);
+ if (::lockf(fd, F_TLOCK, 0) < 0) {
+ ::close(fd);
+ throw ErrnoException("Cannot lock " + path, errno);
+ }
+ impl.reset(new LockFilePrivate(fd));
+}
+
+LockFile::~LockFile() {
+ if (impl) {
+ int f = impl->fd;
+ if (f >= 0) {
+ (void) ::lockf(f, F_ULOCK, 0); // Suppress warnings about ignoring return value.
+ ::close(f);
+ impl->fd = -1;
+ }
+ }
+}
+
+pid_t LockFile::readPid(void) const {
+ if (!impl)
+ throw Exception("Lock file not open");
+
+ pid_t pid;
+ int desired_read = sizeof(pid_t);
+ if (desired_read > ::read(impl->fd, &pid, desired_read) ) {
+ throw Exception("Cannot read lock file " + path);
+ }
+ return pid;
+}
+
+void LockFile::writePid(void) {
+ if (!impl)
+ throw Exception("Lock file not open");
+
+ pid_t pid = getpid();
+ int desired_write = sizeof(pid_t);
+ if (desired_write > ::write(impl->fd, &pid, desired_write)) {
+ throw Exception("Cannot write lock file " + path);
+ }
+}
+
+}} /* namespace qpid::sys */
diff --git a/RC9/qpid/cpp/src/qpid/sys/posix/Mutex.cpp b/RC9/qpid/cpp/src/qpid/sys/posix/Mutex.cpp
new file mode 100644
index 0000000000..0e1f0d30c2
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/posix/Mutex.cpp
@@ -0,0 +1,46 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/sys/Mutex.h"
+
+namespace qpid {
+namespace sys {
+
+/**
+ * Initialise a recursive mutex attr for use in creating mutexes later
+ * (we use pthread_once to make sure it is initialised exactly once)
+ */
+
+namespace {
+pthread_once_t onceControl = PTHREAD_ONCE_INIT;
+pthread_mutexattr_t mutexattr;
+
+void initMutexattr() {
+ pthread_mutexattr_init(&mutexattr);
+ pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);
+}
+}
+
+const pthread_mutexattr_t* Mutex::getAttribute() {
+ pthread_once(&onceControl, initMutexattr);
+ return &mutexattr;
+}
+
+}} // namespace qpid::sys
diff --git a/RC9/qpid/cpp/src/qpid/sys/posix/Mutex.h b/RC9/qpid/cpp/src/qpid/sys/posix/Mutex.h
new file mode 100644
index 0000000000..cd5a8affd4
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/posix/Mutex.h
@@ -0,0 +1,158 @@
+#ifndef _sys_posix_Mutex_h
+#define _sys_posix_Mutex_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "check.h"
+
+#include <pthread.h>
+#include <boost/noncopyable.hpp>
+
+namespace qpid {
+namespace sys {
+
+class Condition;
+
+/**
+ * Mutex lock.
+ */
+class Mutex : private boost::noncopyable {
+ friend class Condition;
+ static const pthread_mutexattr_t* getAttribute();
+
+public:
+ typedef ::qpid::sys::ScopedLock<Mutex> ScopedLock;
+ typedef ::qpid::sys::ScopedUnlock<Mutex> ScopedUnlock;
+
+ inline Mutex();
+ inline ~Mutex();
+ inline void lock();
+ inline void unlock();
+ inline bool trylock();
+
+
+protected:
+ pthread_mutex_t mutex;
+};
+
+/**
+ * RW lock.
+ */
+class RWlock : private boost::noncopyable {
+ friend class Condition;
+
+public:
+ typedef ::qpid::sys::ScopedRlock<RWlock> ScopedRlock;
+ typedef ::qpid::sys::ScopedWlock<RWlock> ScopedWlock;
+
+ inline RWlock();
+ inline ~RWlock();
+ inline void wlock(); // will write-lock
+ inline void rlock(); // will read-lock
+ inline void unlock();
+ inline void trywlock(); // will write-try
+ inline void tryrlock(); // will read-try
+
+protected:
+ pthread_rwlock_t rwlock;
+};
+
+
+/**
+ * PODMutex is a POD, can be static-initialized with
+ * PODMutex m = QPID_PODMUTEX_INITIALIZER
+ */
+struct PODMutex
+{
+ typedef ::qpid::sys::ScopedLock<PODMutex> ScopedLock;
+
+ inline void lock();
+ inline void unlock();
+ inline bool trylock();
+
+ // Must be public to be a POD:
+ pthread_mutex_t mutex;
+};
+
+#define QPID_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER }
+
+void PODMutex::lock() {
+ QPID_POSIX_ASSERT_THROW_IF(pthread_mutex_lock(&mutex));
+}
+
+void PODMutex::unlock() {
+ QPID_POSIX_ASSERT_THROW_IF(pthread_mutex_unlock(&mutex));
+}
+
+bool PODMutex::trylock() {
+ return pthread_mutex_trylock(&mutex) == 0;
+}
+
+Mutex::Mutex() {
+ QPID_POSIX_ASSERT_THROW_IF(pthread_mutex_init(&mutex, getAttribute()));
+}
+
+Mutex::~Mutex(){
+ QPID_POSIX_ASSERT_THROW_IF(pthread_mutex_destroy(&mutex));
+}
+
+void Mutex::lock() {
+ QPID_POSIX_ASSERT_THROW_IF(pthread_mutex_lock(&mutex));
+}
+
+void Mutex::unlock() {
+ QPID_POSIX_ASSERT_THROW_IF(pthread_mutex_unlock(&mutex));
+}
+
+bool Mutex::trylock() {
+ return pthread_mutex_trylock(&mutex) == 0;
+}
+
+
+RWlock::RWlock() {
+ QPID_POSIX_ASSERT_THROW_IF(pthread_rwlock_init(&rwlock, NULL));
+}
+
+RWlock::~RWlock(){
+ QPID_POSIX_ASSERT_THROW_IF(pthread_rwlock_destroy(&rwlock));
+}
+
+void RWlock::wlock() {
+ QPID_POSIX_ASSERT_THROW_IF(pthread_rwlock_wrlock(&rwlock));
+}
+
+void RWlock::rlock() {
+ QPID_POSIX_ASSERT_THROW_IF(pthread_rwlock_rdlock(&rwlock));
+}
+
+void RWlock::unlock() {
+ QPID_POSIX_ASSERT_THROW_IF(pthread_rwlock_unlock(&rwlock));
+}
+
+void RWlock::trywlock() {
+ QPID_POSIX_ASSERT_THROW_IF(pthread_rwlock_trywrlock(&rwlock));
+}
+
+void RWlock::tryrlock() {
+ QPID_POSIX_ASSERT_THROW_IF(pthread_rwlock_tryrdlock(&rwlock));
+}
+
+
+}}
+#endif /*!_sys_posix_Mutex_h*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/posix/PollableCondition.cpp b/RC9/qpid/cpp/src/qpid/sys/posix/PollableCondition.cpp
new file mode 100644
index 0000000000..0c55fd3c0d
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/posix/PollableCondition.cpp
@@ -0,0 +1,96 @@
+#ifndef QPID_SYS_LINUX_POLLABLECONDITION_CPP
+#define QPID_SYS_LINUX_POLLABLECONDITION_CPP
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "PollableCondition.h"
+#include "qpid/sys/posix/PrivatePosix.h"
+#include "qpid/Exception.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+
+namespace qpid {
+namespace sys {
+
+PollableCondition::PollableCondition() : IOHandle(new sys::IOHandlePrivate) {
+ int fds[2];
+ if (::pipe(fds) == -1)
+ throw ErrnoException(QPID_MSG("Can't create PollableCondition"));
+ impl->fd = fds[0];
+ writeFd = fds[1];
+ if (::fcntl(impl->fd, F_SETFL, O_NONBLOCK) == -1)
+ throw ErrnoException(QPID_MSG("Can't create PollableCondition"));
+ if (::fcntl(writeFd, F_SETFL, O_NONBLOCK) == -1)
+ throw ErrnoException(QPID_MSG("Can't create PollableCondition"));
+}
+
+bool PollableCondition::clear() {
+ char buf[256];
+ ssize_t n;
+ bool wasSet = false;
+ while ((n = ::read(impl->fd, buf, sizeof(buf))) > 0)
+ wasSet = true;
+ if (n == -1 && errno != EAGAIN) throw ErrnoException(QPID_MSG("Error clearing PollableCondition"));
+ return wasSet;
+}
+
+void PollableCondition::set() {
+ static const char dummy=0;
+ ssize_t n = ::write(writeFd, &dummy, 1);
+ if (n == -1 && errno != EAGAIN) throw ErrnoException("Error setting PollableCondition");
+}
+
+
+#if 0
+// FIXME aconway 2008-08-12: More efficient Linux implementation using
+// eventfd system call. Move to separate file & do configure.ac test
+// to enable this when ::eventfd() is available.
+
+#include <sys/eventfd.h>
+
+namespace qpid {
+namespace sys {
+
+PollableCondition::PollableCondition() : IOHandle(new sys::IOHandlePrivate) {
+ impl->fd = ::eventfd(0, 0);
+ if (impl->fd < 0) throw ErrnoException("conditionfd() failed");
+}
+
+bool PollableCondition::clear() {
+ char buf[8];
+ ssize_t n = ::read(impl->fd, buf, 8);
+ if (n != 8) throw ErrnoException("read failed on conditionfd");
+ return *reinterpret_cast<uint64_t*>(buf);
+}
+
+void PollableCondition::set() {
+ static const uint64_t value=1;
+ ssize_t n = ::write(impl->fd, reinterpret_cast<const void*>(&value), 8);
+ if (n != 8) throw ErrnoException("write failed on conditionfd");
+}
+
+#endif
+
+}} // namespace qpid::sys
+
+#endif /*!QPID_SYS_LINUX_POLLABLECONDITION_CPP*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/posix/PollableCondition.h b/RC9/qpid/cpp/src/qpid/sys/posix/PollableCondition.h
new file mode 100644
index 0000000000..4ec277b0ec
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/posix/PollableCondition.h
@@ -0,0 +1,56 @@
+#ifndef QPID_SYS_POSIX_POLLABLECONDITION_H
+#define QPID_SYS_POSIX_POLLABLECONDITION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/IOHandle.h"
+
+namespace qpid {
+namespace sys {
+
+/**
+ * A pollable condition to integrate in-process conditions with IO
+ * conditions in a polling loop.
+ *
+ * Setting the condition makes it readable for a poller.
+ *
+ * Writable/disconnected conditions are undefined and should not be
+ * polled for.
+ */
+class PollableCondition : public sys::IOHandle {
+ public:
+ PollableCondition();
+
+ /** Set the condition, triggers readable in a poller. */
+ void set();
+
+ /** Get the current state of the condition, then clear it.
+ *@return The state of the condition before it was cleared.
+ */
+ bool clear();
+
+ private:
+ int writeFd;
+};
+}} // namespace qpid::sys
+
+#endif /*!QPID_SYS_POSIX_POLLABLECONDITION_H*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/posix/PrivatePosix.h b/RC9/qpid/cpp/src/qpid/sys/posix/PrivatePosix.h
new file mode 100644
index 0000000000..33c0cd81bc
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/posix/PrivatePosix.h
@@ -0,0 +1,52 @@
+#ifndef _sys_posix_PrivatePosix_h
+#define _sys_posix_PrivatePosix_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Time.h"
+
+struct timespec;
+struct timeval;
+
+namespace qpid {
+namespace sys {
+
+// Private Time related implementation details
+struct timespec& toTimespec(struct timespec& ts, const Duration& t);
+struct timeval& toTimeval(struct timeval& tv, const Duration& t);
+Duration toTime(const struct timespec& ts);
+
+// Private fd related implementation details
+class IOHandlePrivate {
+public:
+ IOHandlePrivate(int f = -1) :
+ fd(f)
+ {}
+
+ int fd;
+};
+
+int toFd(const IOHandlePrivate* h);
+
+}}
+
+#endif /*!_sys_posix_PrivatePosix_h*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/posix/Shlib.cpp b/RC9/qpid/cpp/src/qpid/sys/posix/Shlib.cpp
new file mode 100644
index 0000000000..62dbfb3dd9
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/posix/Shlib.cpp
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Shlib.h"
+#include "qpid/Exception.h"
+#include <dlfcn.h>
+
+
+namespace qpid {
+namespace sys {
+
+void Shlib::load(const char* name) {
+ dlerror();
+ handle = ::dlopen(name, RTLD_NOW);
+ const char* error = ::dlerror();
+ if (error) {
+ throw Exception(QPID_MSG(error << ": " << name));
+ }
+}
+
+void Shlib::unload() {
+ if (handle) {
+ ::dlerror();
+ ::dlclose(handle);
+ const char* error = ::dlerror();
+ if (error) {
+ throw Exception(QPID_MSG(error));
+ }
+ handle = 0;
+ }
+}
+
+void* Shlib::getSymbol(const char* name) {
+ ::dlerror();
+ void* sym = ::dlsym(handle, name);
+ const char* error = ::dlerror();
+ if (error)
+ throw Exception(QPID_MSG(error << ": " << name));
+ return sym;
+}
+
+}} // namespace qpid::sys
diff --git a/RC9/qpid/cpp/src/qpid/sys/posix/Socket.cpp b/RC9/qpid/cpp/src/qpid/sys/posix/Socket.cpp
new file mode 100644
index 0000000000..415d5293ef
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/posix/Socket.cpp
@@ -0,0 +1,264 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Socket.h"
+
+#include "check.h"
+#include "PrivatePosix.h"
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <cstdlib>
+#include <string.h>
+#include <iostream>
+
+#include <boost/format.hpp>
+
+namespace qpid {
+namespace sys {
+
+namespace {
+std::string getName(int fd, bool local, bool includeService = false)
+{
+ ::sockaddr_storage name; // big enough for any socket address
+ ::socklen_t namelen = sizeof(name);
+
+ int result = -1;
+ if (local) {
+ result = ::getsockname(fd, (::sockaddr*)&name, &namelen);
+ } else {
+ result = ::getpeername(fd, (::sockaddr*)&name, &namelen);
+ }
+
+ QPID_POSIX_CHECK(result);
+
+ char servName[NI_MAXSERV];
+ char dispName[NI_MAXHOST];
+ if (includeService) {
+ if (int rc=::getnameinfo((::sockaddr*)&name, namelen, dispName, sizeof(dispName),
+ servName, sizeof(servName),
+ NI_NUMERICHOST | NI_NUMERICSERV) != 0)
+ throw QPID_POSIX_ERROR(rc);
+ return std::string(dispName) + ":" + std::string(servName);
+
+ } else {
+ if (int rc=::getnameinfo((::sockaddr*)&name, namelen, dispName, sizeof(dispName), 0, 0, NI_NUMERICHOST) != 0)
+ throw QPID_POSIX_ERROR(rc);
+ return dispName;
+ }
+}
+
+std::string getService(int fd, bool local)
+{
+ ::sockaddr_storage name; // big enough for any socket address
+ ::socklen_t namelen = sizeof(name);
+
+ int result = -1;
+ if (local) {
+ result = ::getsockname(fd, (::sockaddr*)&name, &namelen);
+ } else {
+ result = ::getpeername(fd, (::sockaddr*)&name, &namelen);
+ }
+
+ QPID_POSIX_CHECK(result);
+
+ char servName[NI_MAXSERV];
+ if (int rc=::getnameinfo((::sockaddr*)&name, namelen, 0, 0,
+ servName, sizeof(servName),
+ NI_NUMERICHOST | NI_NUMERICSERV) != 0)
+ throw QPID_POSIX_ERROR(rc);
+ return servName;
+}
+}
+
+Socket::Socket() :
+ IOHandle(new IOHandlePrivate)
+{
+ createTcp();
+}
+
+Socket::Socket(IOHandlePrivate* h) :
+ IOHandle(h)
+{}
+
+void Socket::createTcp() const
+{
+ int& socket = impl->fd;
+ if (socket != -1) Socket::close();
+ int s = ::socket (PF_INET, SOCK_STREAM, 0);
+ if (s < 0) throw QPID_POSIX_ERROR(errno);
+ socket = s;
+}
+
+void Socket::setTimeout(const Duration& interval) const
+{
+ const int& socket = impl->fd;
+ struct timeval tv;
+ toTimeval(tv, interval);
+ setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
+ setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+}
+
+void Socket::setNonblocking() const {
+ QPID_POSIX_CHECK(::fcntl(impl->fd, F_SETFL, O_NONBLOCK));
+}
+
+namespace {
+const char* h_errstr(int e) {
+ switch (e) {
+ case HOST_NOT_FOUND: return "Host not found";
+ case NO_ADDRESS: return "Name does not have an IP address";
+ case TRY_AGAIN: return "A temporary error occurred on an authoritative name server.";
+ case NO_RECOVERY: return "Non-recoverable name server error";
+ default: return "Unknown error";
+ }
+}
+}
+
+void Socket::connect(const std::string& host, uint16_t port) const
+{
+ std::stringstream namestream;
+ namestream << host << ":" << port;
+ connectname = namestream.str();
+
+ const int& socket = impl->fd;
+ struct sockaddr_in name;
+ name.sin_family = AF_INET;
+ name.sin_port = htons(port);
+ // TODO: Be good to make this work for IPv6 as well as IPv4
+ // Use more modern lookup functions
+ struct hostent* hp = gethostbyname ( host.c_str() );
+ if (hp == 0)
+ throw Exception(QPID_MSG("Cannot resolve " << host << ": " << h_errstr(h_errno)));
+ ::memcpy(&name.sin_addr.s_addr, hp->h_addr_list[0], hp->h_length);
+ if ((::connect(socket, (struct sockaddr*)(&name), sizeof(name)) < 0) &&
+ (errno != EINPROGRESS))
+ throw qpid::Exception(QPID_MSG(strError(errno) << ": " << host << ":" << port));
+}
+
+void
+Socket::close() const
+{
+ int& socket = impl->fd;
+ if (socket == -1) return;
+ if (::close(socket) < 0) throw QPID_POSIX_ERROR(errno);
+ socket = -1;
+}
+
+int Socket::listen(uint16_t port, int backlog) const
+{
+ const int& socket = impl->fd;
+ int yes=1;
+ QPID_POSIX_CHECK(setsockopt(socket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes)));
+ struct sockaddr_in name;
+ name.sin_family = AF_INET;
+ name.sin_port = htons(port);
+ name.sin_addr.s_addr = 0;
+ if (::bind(socket, (struct sockaddr*)&name, sizeof(name)) < 0)
+ throw Exception(QPID_MSG("Can't bind to port " << port << ": " << strError(errno)));
+ if (::listen(socket, backlog) < 0)
+ throw Exception(QPID_MSG("Can't listen on port " << port << ": " << strError(errno)));
+
+ socklen_t namelen = sizeof(name);
+ if (::getsockname(socket, (struct sockaddr*)&name, &namelen) < 0)
+ throw QPID_POSIX_ERROR(errno);
+
+ return ntohs(name.sin_port);
+}
+
+Socket* Socket::accept(struct sockaddr *addr, socklen_t *addrlen) const
+{
+ int afd = ::accept(impl->fd, addr, addrlen);
+ if ( afd >= 0)
+ return new Socket(new IOHandlePrivate(afd));
+ else if (errno == EAGAIN)
+ return 0;
+ else throw QPID_POSIX_ERROR(errno);
+}
+
+int Socket::read(void *buf, size_t count) const
+{
+ return ::read(impl->fd, buf, count);
+}
+
+int Socket::write(const void *buf, size_t count) const
+{
+ return ::write(impl->fd, buf, count);
+}
+
+std::string Socket::getSockname() const
+{
+ return getName(impl->fd, true);
+}
+
+std::string Socket::getPeername() const
+{
+ return getName(impl->fd, false);
+}
+
+std::string Socket::getPeerAddress() const
+{
+ if (!connectname.empty())
+ return std::string (connectname);
+ return getName(impl->fd, false, true);
+}
+
+std::string Socket::getLocalAddress() const
+{
+ return getName(impl->fd, true, true);
+}
+
+uint16_t Socket::getLocalPort() const
+{
+ return std::atoi(getService(impl->fd, true).c_str());
+}
+
+uint16_t Socket::getRemotePort() const
+{
+ return atoi(getService(impl->fd, true).c_str());
+}
+
+int Socket::getError() const
+{
+ int result;
+ socklen_t rSize = sizeof (result);
+
+ if (::getsockopt(impl->fd, SOL_SOCKET, SO_ERROR, &result, &rSize) < 0)
+ throw QPID_POSIX_ERROR(errno);
+
+ return result;
+}
+
+void Socket::setTcpNoDelay(bool nodelay) const
+{
+ if (nodelay) {
+ int flag = 1;
+ int result = setsockopt(impl->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag));
+ QPID_POSIX_CHECK(result);
+ }
+}
+
+}} // namespace qpid::sys
diff --git a/RC9/qpid/cpp/src/qpid/sys/posix/StrError.cpp b/RC9/qpid/cpp/src/qpid/sys/posix/StrError.cpp
new file mode 100644
index 0000000000..633e20213c
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/posix/StrError.cpp
@@ -0,0 +1,41 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/StrError.h"
+
+#include <string.h>
+
+namespace qpid {
+namespace sys {
+
+std::string strError(int err) {
+ char buf[512] = "Unknown error";
+#ifdef _GNU_SOURCE
+ // GNU strerror_r returns the message
+ return ::strerror_r(err, buf, sizeof(buf));
+#else
+ // POSIX strerror_r doesn't return the buffer
+ ::strerror_r(err, buf, sizeof(buf));
+ return std::string(buf);
+#endif
+}
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/sys/posix/SystemInfo.cpp b/RC9/qpid/cpp/src/qpid/sys/posix/SystemInfo.cpp
new file mode 100755
index 0000000000..938d4861c4
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/posix/SystemInfo.cpp
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/SystemInfo.h"
+
+#include <sys/ioctl.h>
+#include <sys/utsname.h>
+#include <net/if.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#ifndef HOST_NAME_MAX
+# define HOST_NAME_MAX 256
+#endif
+
+using namespace std;
+
+namespace qpid {
+namespace sys {
+
+long SystemInfo::concurrency() {
+#ifdef _SC_NPROCESSORS_ONLN // Linux specific.
+ return sysconf(_SC_NPROCESSORS_ONLN);
+#else
+ return -1;
+#endif
+}
+
+bool SystemInfo::getLocalHostname (TcpAddress &address) {
+ char name[HOST_NAME_MAX];
+ if (::gethostname(name, sizeof(name)) != 0)
+ return false;
+ address.host = name;
+ return true;
+}
+
+static const string LOCALHOST("127.0.0.1");
+
+void SystemInfo::getLocalIpAddresses (uint16_t port,
+ std::vector<Address> &addrList) {
+ int s = socket (PF_INET, SOCK_STREAM, 0);
+ for (int i=1;;i++) {
+ struct ifreq ifr;
+ ifr.ifr_ifindex = i;
+ if (::ioctl (s, SIOCGIFNAME, &ifr) < 0)
+ break;
+ /* now ifr.ifr_name is set */
+ if (::ioctl (s, SIOCGIFADDR, &ifr) < 0)
+ continue;
+ struct sockaddr_in *sin = (struct sockaddr_in *) &ifr.ifr_addr;
+ string addr(inet_ntoa(sin->sin_addr));
+ if (addr != LOCALHOST)
+ addrList.push_back(TcpAddress(addr, port));
+ }
+ if (addrList.empty()) {
+ addrList.push_back(TcpAddress(LOCALHOST, port));
+ }
+ close (s);
+}
+
+void SystemInfo::getSystemId (std::string &osName,
+ std::string &nodeName,
+ std::string &release,
+ std::string &version,
+ std::string &machine)
+{
+ struct utsname _uname;
+ if (uname (&_uname) == 0)
+ {
+ osName = _uname.sysname;
+ nodeName = _uname.nodename;
+ release = _uname.release;
+ version = _uname.version;
+ machine = _uname.machine;
+ }
+}
+
+uint32_t SystemInfo::getProcessId()
+{
+ return (uint32_t) ::getpid();
+}
+
+uint32_t SystemInfo::getParentProcessId()
+{
+ return (uint32_t) ::getppid();
+}
+
+
+
+}} // namespace qpid::sys
diff --git a/RC9/qpid/cpp/src/qpid/sys/posix/Thread.cpp b/RC9/qpid/cpp/src/qpid/sys/posix/Thread.cpp
new file mode 100644
index 0000000000..bb5641bc53
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/posix/Thread.cpp
@@ -0,0 +1,75 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Thread.h"
+
+#include "qpid/sys/Runnable.h"
+#include "check.h"
+
+#include <pthread.h>
+
+namespace qpid {
+namespace sys {
+
+namespace {
+void* runRunnable(void* p)
+{
+ static_cast<Runnable*>(p)->run();
+ return 0;
+}
+}
+
+struct ThreadPrivate {
+ pthread_t thread;
+
+ ThreadPrivate(Runnable* runnable) {
+ QPID_POSIX_ASSERT_THROW_IF(::pthread_create(&thread, NULL, runRunnable, runnable));
+ }
+
+ ThreadPrivate() : thread(::pthread_self()) {}
+};
+
+Thread::Thread() {}
+
+Thread::Thread(Runnable* runnable) : impl(new ThreadPrivate(runnable)) {}
+
+Thread::Thread(Runnable& runnable) : impl(new ThreadPrivate(&runnable)) {}
+
+void Thread::join(){
+ if (impl) {
+ QPID_POSIX_ASSERT_THROW_IF(::pthread_join(impl->thread, 0));
+ }
+}
+
+unsigned long Thread::id() {
+ if (impl)
+ return impl->thread;
+ else
+ return 0;
+}
+
+Thread Thread::current() {
+ Thread t;
+ t.impl.reset(new ThreadPrivate());
+ return t;
+}
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/sys/posix/Time.cpp b/RC9/qpid/cpp/src/qpid/sys/posix/Time.cpp
new file mode 100644
index 0000000000..d8d0a58d2e
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/posix/Time.cpp
@@ -0,0 +1,110 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "PrivatePosix.h"
+
+#include "qpid/sys/Time.h"
+#include <ostream>
+#include <time.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+namespace {
+int64_t max_abstime() { return std::numeric_limits<int64_t>::max(); }
+}
+
+namespace qpid {
+namespace sys {
+
+AbsTime::AbsTime(const AbsTime& t, const Duration& d) :
+ timepoint(d == Duration::max() ? max_abstime() : t.timepoint+d.nanosecs)
+{}
+
+AbsTime AbsTime::FarFuture() {
+ AbsTime ff; ff.timepoint = max_abstime(); return ff;
+}
+
+AbsTime AbsTime::now() {
+ struct timespec ts;
+ ::clock_gettime(CLOCK_REALTIME, &ts);
+ AbsTime time_now;
+ time_now.timepoint = toTime(ts).nanosecs;
+ return time_now;
+}
+
+Duration::Duration(const AbsTime& time0) :
+ nanosecs(time0.timepoint)
+{}
+
+Duration::Duration(const AbsTime& start, const AbsTime& finish) :
+ nanosecs(finish.timepoint - start.timepoint)
+{}
+
+struct timespec& toTimespec(struct timespec& ts, const Duration& t) {
+ ts.tv_sec = t / TIME_SEC;
+ ts.tv_nsec = t % TIME_SEC;
+ return ts;
+}
+
+struct timeval& toTimeval(struct timeval& tv, const Duration& t) {
+ tv.tv_sec = t/TIME_SEC;
+ tv.tv_usec = (t%TIME_SEC)/TIME_USEC;
+ return tv;
+}
+
+Duration toTime(const struct timespec& ts) {
+ return ts.tv_sec*TIME_SEC + ts.tv_nsec;
+}
+
+std::ostream& operator<<(std::ostream& o, const Duration& d) {
+ return o << int64_t(d) << "ns";
+}
+
+std::ostream& operator<<(std::ostream& o, const AbsTime& t) {
+ static const char * month_abbrevs[] = {
+ "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"
+ };
+ struct tm * timeinfo;
+ time_t rawtime(t.timepoint/TIME_SEC);
+ timeinfo = localtime (&rawtime);
+ char time_string[100];
+ sprintf ( time_string,
+ "%d-%s-%02d %02d:%02d:%02d",
+ 1900 + timeinfo->tm_year,
+ month_abbrevs[timeinfo->tm_mon],
+ timeinfo->tm_mday,
+ timeinfo->tm_hour,
+ timeinfo->tm_min,
+ timeinfo->tm_sec
+ );
+ return o << time_string;
+}
+
+void sleep(int secs) {
+ ::sleep(secs);
+}
+
+void usleep(uint64_t usecs) {
+ ::usleep(usecs);
+}
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/sys/posix/Time.h b/RC9/qpid/cpp/src/qpid/sys/posix/Time.h
new file mode 100755
index 0000000000..62d734c816
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/posix/Time.h
@@ -0,0 +1,34 @@
+#ifndef QPID_SYS_POSIX_TIME_H
+#define QPID_SYS_POSIX_TIME_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/sys/IntegerTypes.h"
+
+namespace qpid {
+namespace sys {
+
+/**
+ * Class to represent an instant in time.
+ */
+typedef int64_t TimePrivate;
+
+}} // namespace qpid::sys
+
+#endif /*!QPID_SYS_POSIX_TIME_H*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/posix/check.h b/RC9/qpid/cpp/src/qpid/sys/posix/check.h
new file mode 100644
index 0000000000..f3031b7593
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/posix/check.h
@@ -0,0 +1,49 @@
+#ifndef _posix_check_h
+#define _posix_check_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/Exception.h"
+
+#include <cerrno>
+#include <assert.h>
+#include <stdio.h>
+
+#define QPID_POSIX_ERROR(ERRNO) qpid::Exception(QPID_MSG(qpid::sys::strError(ERRNO)))
+
+/** THROW QPID_POSIX_ERROR(errno) if RESULT is less than zero */
+#define QPID_POSIX_CHECK(RESULT) \
+ if ((RESULT) < 0) throw QPID_POSIX_ERROR((errno))
+
+/** Throw a posix error if ERRNO is non-zero */
+#define QPID_POSIX_THROW_IF(ERRNO) \
+ do { int e=(ERRNO); if (e) throw QPID_POSIX_ERROR(e); } while(0)
+
+/** Same as _THROW_IF in a release build, but abort a debug build */
+#ifdef NDEBUG
+#define QPID_POSIX_ASSERT_THROW_IF(ERRNO) QPID_POSIX_THROW_IF(ERRNO)
+#else
+#define QPID_POSIX_ASSERT_THROW_IF(ERRNO) \
+ do { int e=(ERRNO); if (e) { errno=e; ::perror(0); assert(0); } } while(0)
+#endif
+
+#endif /*!_posix_check_h*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/rdma/RdmaClient.cpp b/RC9/qpid/cpp/src/qpid/sys/rdma/RdmaClient.cpp
new file mode 100644
index 0000000000..0d3dd83131
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/rdma/RdmaClient.cpp
@@ -0,0 +1,207 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "RdmaIO.h"
+#include "qpid/sys/Time.h"
+
+#include <netdb.h>
+#include <arpa/inet.h>
+
+#include <vector>
+#include <string>
+#include <iostream>
+#include <algorithm>
+#include <cmath>
+#include <boost/bind.hpp>
+
+using std::vector;
+using std::string;
+using std::cout;
+using std::cerr;
+using std::copy;
+using std::rand;
+
+using qpid::sys::Poller;
+using qpid::sys::Dispatcher;
+using qpid::sys::AbsTime;
+using qpid::sys::Duration;
+using qpid::sys::TIME_SEC;
+using qpid::sys::TIME_INFINITE;
+
+// count of messages
+int64_t smsgs = 0;
+int64_t sbytes = 0;
+int64_t rmsgs = 0;
+int64_t rbytes = 0;
+
+int target = 1000000;
+int msgsize = 200;
+AbsTime startTime;
+Duration sendingDuration(TIME_INFINITE);
+Duration fullTestDuration(TIME_INFINITE);
+
+vector<char> testString;
+
+void write(Rdma::AsynchIO& aio) {
+ while (aio.writable()) {
+ if (smsgs >= target)
+ return;
+ Rdma::Buffer* b = aio.getBuffer();
+ std::copy(testString.begin(), testString.end(), b->bytes);
+ b->dataCount = msgsize;
+ aio.queueWrite(b);
+ ++smsgs;
+ sbytes += msgsize;
+ }
+}
+
+void dataError(Rdma::AsynchIO&) {
+ cout << "Data error:\n";
+}
+
+void data(Poller::shared_ptr p, Rdma::AsynchIO& aio, Rdma::Buffer* b) {
+ ++rmsgs;
+ rbytes += b->dataCount;
+
+ // When all messages have been recvd stop
+ if (rmsgs < target) {
+ write(aio);
+ } else {
+ fullTestDuration = std::min(fullTestDuration, Duration(startTime, AbsTime::now()));
+ if (aio.incompletedWrites() == 0)
+ p->shutdown();
+ }
+}
+
+void full(Rdma::AsynchIO& a, Rdma::Buffer* b) {
+ // Warn as we shouldn't get here anymore
+ cerr << "!";
+
+ // Don't need to keep buffer just adjust the counts
+ --smsgs;
+ sbytes -= b->dataCount;
+
+ // Give buffer back
+ a.returnBuffer(b);
+}
+
+void idle(Poller::shared_ptr p, Rdma::AsynchIO& aio) {
+ if (smsgs < target) {
+ write(aio);
+ } else {
+ sendingDuration = std::min(sendingDuration, Duration(startTime, AbsTime::now()));
+ if (rmsgs >= target && aio.incompletedWrites() == 0)
+ p->shutdown();
+ }
+}
+
+void connected(Poller::shared_ptr poller, Rdma::Connection::intrusive_ptr& ci, const Rdma::ConnectionParams& cp) {
+ cout << "Connected\n";
+ Rdma::QueuePair::intrusive_ptr q = ci->getQueuePair();
+
+ Rdma::AsynchIO* aio = new Rdma::AsynchIO(ci->getQueuePair(),
+ cp.maxRecvBufferSize, cp.initialXmitCredit , Rdma::DEFAULT_WR_ENTRIES,
+ boost::bind(&data, poller, _1, _2),
+ boost::bind(&idle, poller, _1),
+ &full,
+ dataError);
+
+ startTime = AbsTime::now();
+ write(*aio);
+
+ aio->start(poller);
+}
+
+void disconnected(boost::shared_ptr<Poller> p, Rdma::Connection::intrusive_ptr&) {
+ cout << "Disconnected\n";
+ p->shutdown();
+}
+
+void connectionError(boost::shared_ptr<Poller> p, Rdma::Connection::intrusive_ptr&, const Rdma::ErrorType) {
+ cout << "Connection error\n";
+ p->shutdown();
+}
+
+void rejected(boost::shared_ptr<Poller> p, Rdma::Connection::intrusive_ptr&, const Rdma::ConnectionParams&) {
+ cout << "Connection rejected\n";
+ p->shutdown();
+}
+
+int main(int argc, char* argv[]) {
+ vector<string> args(&argv[0], &argv[argc]);
+
+ ::addrinfo *res;
+ ::addrinfo hints = {};
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ string port = (args.size() < 3) ? "20079" : args[2];
+ int n = ::getaddrinfo(args[1].c_str(), port.c_str(), &hints, &res);
+ if (n<0) {
+ cerr << "Can't find information for: " << args[1] << "\n";
+ return 1;
+ } else {
+ cout << "Connecting to: " << args[1] << ":" << port <<"\n";
+ }
+
+ if (args.size() > 3)
+ msgsize = atoi(args[3].c_str());
+ cout << "Message size: " << msgsize << "\n";
+
+ // Make a random message of that size
+ testString.resize(msgsize);
+ for (int i = 0; i < msgsize; ++i) {
+ testString[i] = 32 + (rand() & 0x3f);
+ }
+
+ try {
+ boost::shared_ptr<Poller> p(new Poller());
+ Dispatcher d(p);
+
+ Rdma::Connector c(
+ *res->ai_addr,
+ Rdma::ConnectionParams(msgsize, Rdma::DEFAULT_WR_ENTRIES),
+ boost::bind(&connected, p, _1, _2),
+ boost::bind(&connectionError, p, _1, _2),
+ boost::bind(&disconnected, p, _1),
+ boost::bind(&rejected, p, _1, _2));
+
+ c.start(p);
+ d.run();
+ } catch (Rdma::Exception& e) {
+ int err = e.getError();
+ cerr << "Error: " << e.what() << "(" << err << ")\n";
+ }
+
+ cout
+ << "Sent: " << smsgs
+ << "msgs (" << sbytes
+ << "bytes) in: " << double(sendingDuration)/TIME_SEC
+ << "s: " << double(smsgs)*TIME_SEC/sendingDuration
+ << "msgs/s(" << double(sbytes)*TIME_SEC/sendingDuration
+ << "bytes/s)\n";
+ cout
+ << "Recd: " << rmsgs
+ << "msgs (" << rbytes
+ << "bytes) in: " << double(fullTestDuration)/TIME_SEC
+ << "s: " << double(rmsgs)*TIME_SEC/fullTestDuration
+ << "msgs/s(" << double(rbytes)*TIME_SEC/fullTestDuration
+ << "bytes/s)\n";
+
+}
diff --git a/RC9/qpid/cpp/src/qpid/sys/rdma/RdmaIO.cpp b/RC9/qpid/cpp/src/qpid/sys/rdma/RdmaIO.cpp
new file mode 100644
index 0000000000..77e766dd79
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/rdma/RdmaIO.cpp
@@ -0,0 +1,617 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "RdmaIO.h"
+
+#include "qpid/log/Statement.h"
+
+
+#include <iostream>
+#include <boost/bind.hpp>
+
+using qpid::sys::DispatchHandle;
+using qpid::sys::Poller;
+
+namespace Rdma {
+ AsynchIO::AsynchIO(
+ QueuePair::intrusive_ptr q,
+ int size,
+ int xCredit,
+ int rCount,
+ ReadCallback rc,
+ IdleCallback ic,
+ FullCallback fc,
+ ErrorCallback ec
+ ) :
+ qp(q),
+ dataHandle(*qp, boost::bind(&AsynchIO::dataEvent, this, _1), 0, 0),
+ bufferSize(size),
+ recvCredit(0),
+ xmitCredit(xCredit),
+ recvBufferCount(rCount),
+ xmitBufferCount(xCredit),
+ outstandingWrites(0),
+ closed(false),
+ deleting(false),
+ state(IDLE),
+ readCallback(rc),
+ idleCallback(ic),
+ fullCallback(fc),
+ errorCallback(ec)
+ {
+ qp->nonblocking();
+ qp->notifyRecv();
+ qp->notifySend();
+
+ // Prepost some recv buffers before we go any further
+ for (int i = 0; i<recvBufferCount; ++i) {
+ // Allocate recv buffer
+ Buffer* b = qp->createBuffer(bufferSize);
+ buffers.push_front(b);
+ b->dataCount = b->byteCount;
+ qp->postRecv(b);
+ }
+
+ for (int i = 0; i<xmitBufferCount; ++i) {
+ // Allocate xmit buffer
+ Buffer* b = qp->createBuffer(bufferSize);
+ buffers.push_front(b);
+ bufferQueue.push_front(b);
+ b->dataCount = 0;
+ b->dataStart = 0;
+ }
+ }
+
+ AsynchIO::~AsynchIO() {
+ // Warn if we are deleting whilst there are still unreclaimed write buffers
+ if ( outstandingWrites>0 )
+ QPID_LOG(error, "RDMA: qp=" << qp << ": Deleting queue before all write buffers finished");
+
+ // Turn off callbacks (before doing the deletes)
+ dataHandle.stopWatch();
+
+ // The buffers ptr_deque automatically deletes all the buffers we've allocated
+ // TODO: It might turn out to be more efficient in high connection loads to reuse the
+ // buffers rather than having to reregister them all the time (this would be straightforward if all
+ // connections haver the same buffer size and harder otherwise)
+ }
+
+ void AsynchIO::start(Poller::shared_ptr poller) {
+ dataHandle.startWatch(poller);
+ }
+
+ // Mark for deletion/Delete this object when we have no outstanding writes
+ void AsynchIO::deferDelete() {
+ State oldState;
+ State newState;
+ bool doReturn;
+ //qpid::sys::ScopedLock<qpid::sys::Mutex> l(stateLock);
+ // It is safe to assign to deleting here as we either delete ourselves
+ // before leaving this function or deleting is set on exit
+ do {
+ newState = oldState = state.get();
+ doReturn = false;
+ if (outstandingWrites > 0 || oldState != IDLE) {
+ deleting = true;
+ doReturn = true;
+ } else{
+ newState = DELETED; // Stop any read callback before the dataHandle.stopWatch() in the destructor
+ }
+ } while (!state.boolCompareAndSwap(oldState, newState));
+ if (doReturn) {
+ return;
+ }
+ delete this;
+ }
+
+ void AsynchIO::queueWrite(Buffer* buff) {
+ // Make sure we don't overrun our available buffers
+ // either at our end or the known available at the peers end
+ if (writable()) {
+ // TODO: We might want to batch up sending credit
+ if (recvCredit > 0) {
+ int creditSent = recvCredit & ~FlagsMask;
+ qp->postSend(creditSent, buff);
+ recvCredit -= creditSent;
+ } else {
+ qp->postSend(buff);
+ }
+ ++outstandingWrites;
+ --xmitCredit;
+ } else {
+ if (fullCallback) {
+ fullCallback(*this, buff);
+ } else {
+ QPID_LOG(error, "RDMA: qp=" << qp << ": Write queue full, but no callback, throwing buffer away");
+ returnBuffer(buff);
+ }
+ }
+ }
+
+ // Mark now closed (so we don't accept any more writes or make any idle callbacks)
+ void AsynchIO::queueWriteClose() {
+ // Don't think we actually need to lock here as transition is 1 way only to closed
+ closed = true;
+ }
+
+ void AsynchIO::notifyPendingWrite() {
+ // As notifyPendingWrite can be called on an arbitrary thread it must check whether we are processing or not.
+ // If we are then we just return as we know that we will eventually do the idle callback anyway.
+ //
+ // qpid::sys::ScopedLock<qpid::sys::Mutex> l(stateLock);
+ // We can get here in any state (as the caller could be in any thread)
+ State oldState;
+ State newState;
+ bool doReturn;
+ do {
+ newState = oldState = state.get();
+ doReturn = false;
+ switch (oldState) {
+ case NOTIFY_WRITE:
+ case PENDING_NOTIFY:
+ // We only need to note a pending notify if we're already doing a notify as data processing
+ // is always followed by write notification processing
+ newState = PENDING_NOTIFY;
+ doReturn = true;
+ break;
+ case PENDING_DATA:
+ doReturn = true;
+ break;
+ case DATA:
+ // Only need to return here as data processing will do the idleCallback itself anyway
+ doReturn = true;
+ break;
+ case IDLE:
+ newState = NOTIFY_WRITE;
+ break;
+ case DELETED:
+ assert(oldState!=DELETED);
+ doReturn = true;
+ };
+ } while (!state.boolCompareAndSwap(oldState, newState));
+ if (doReturn) {
+ return;
+ }
+
+ doWriteCallback();
+
+ // Keep track of what we need to do so that we can release the lock
+ enum {COMPLETION, NOTIFY, RETURN, EXIT} action;
+ // If there was pending data whilst we were doing this, process it now
+ //
+ // Using NOTIFY_WRITE for both NOTIFY & COMPLETION is a bit strange, but we're making sure we get the
+ // correct result if we reenter notifyPendingWrite(), in which case we want to
+ // end up in PENDING_NOTIFY (entering dataEvent doesn't matter as it only checks
+ // not IDLE)
+ do {
+ //qpid::sys::ScopedLock<qpid::sys::Mutex> l(stateLock);
+ do {
+ newState = oldState = state.get();
+ action = RETURN; // Anything but COMPLETION
+ switch (oldState) {
+ case NOTIFY_WRITE:
+ newState = IDLE;
+ action = (action == COMPLETION) ? EXIT : RETURN;
+ break;
+ case PENDING_DATA:
+ newState = NOTIFY_WRITE;
+ action = COMPLETION;
+ break;
+ case PENDING_NOTIFY:
+ newState = NOTIFY_WRITE;
+ action = NOTIFY;
+ break;
+ default:
+ assert(oldState!=IDLE && oldState!=DATA && oldState!=DELETED);
+ action = RETURN;
+ }
+ } while (!state.boolCompareAndSwap(oldState, newState));
+
+ // Note we only get here if we were in the PENDING_DATA or PENDING_NOTIFY state
+ // so that we do need to process completions or notifications now
+ switch (action) {
+ case COMPLETION:
+ processCompletions();
+ // Fall through
+ case NOTIFY:
+ doWriteCallback();
+ break;
+ case RETURN:
+ return;
+ case EXIT:
+ // If we just processed completions we might need to delete ourselves
+ if (deleting && outstandingWrites == 0) {
+ delete this;
+ }
+ return;
+ }
+ } while (true);
+ }
+
+ void AsynchIO::dataEvent(qpid::sys::DispatchHandle&) {
+ // Keep track of writable notifications
+ // qpid::sys::ScopedLock<qpid::sys::Mutex> l(stateLock);
+ State oldState;
+ State newState;
+ bool doReturn;
+ do {
+ newState = oldState = state.get();
+ doReturn = false;
+ // We're already processing a notification
+ switch (oldState) {
+ case IDLE:
+ newState = DATA;
+ break;
+ default:
+ // Can't get here in DATA state as that would violate the serialisation rules
+ assert( oldState!=DATA );
+ newState = PENDING_DATA;
+ doReturn = true;
+ }
+ } while (!state.boolCompareAndSwap(oldState, newState));
+ if (doReturn) {
+ return;
+ }
+
+ processCompletions();
+
+ //qpid::sys::ScopedLock<qpid::sys::Mutex> l(stateLock);
+ do {
+ newState = oldState = state.get();
+ assert( oldState==DATA );
+ newState = NOTIFY_WRITE;
+ } while (!state.boolCompareAndSwap(oldState, newState));
+
+ do {
+ doWriteCallback();
+
+ // qpid::sys::ScopedLock<qpid::sys::Mutex> l(stateLock);
+ bool doBreak;
+ do {
+ newState = oldState = state.get();
+ doBreak = false;
+ if ( oldState==NOTIFY_WRITE ) {
+ newState = IDLE;
+ doBreak = true;
+ } else {
+ // Can't get DATA/PENDING_DATA here as dataEvent cannot be reentered
+ assert( oldState==PENDING_NOTIFY );
+ newState = NOTIFY_WRITE;
+ }
+ } while (!state.boolCompareAndSwap(oldState, newState));
+ if (doBreak) {
+ break;
+ }
+ } while (true);
+
+ // We might need to delete ourselves
+ if (deleting && outstandingWrites == 0) {
+ delete this;
+ }
+ }
+
+ void AsynchIO::processCompletions() {
+ QueuePair::intrusive_ptr q = qp->getNextChannelEvent();
+
+ // Re-enable notification for queue:
+ // This needs to happen before we could do anything that could generate more work completion
+ // events (ie the callbacks etc. in the following).
+ // This can't make us reenter this code as the handle attached to the completion queue will still be
+ // disabled by the poller until we leave this code
+ qp->notifyRecv();
+ qp->notifySend();
+
+ int recvEvents = 0;
+ int sendEvents = 0;
+
+ // If no event do nothing
+ if (!q)
+ return;
+
+ assert(q == qp);
+
+ // Repeat until no more events
+ do {
+ QueuePairEvent e(qp->getNextEvent());
+ if (!e)
+ break;
+
+ ::ibv_wc_status status = e.getEventStatus();
+ if (status != IBV_WC_SUCCESS) {
+ errorCallback(*this);
+ // TODO: Probably need to flush queues at this point
+ return;
+ }
+
+ // Test if recv (or recv with imm)
+ //::ibv_wc_opcode eventType = e.getEventType();
+ Buffer* b = e.getBuffer();
+ QueueDirection dir = e.getDirection();
+ if (dir == RECV) {
+ ++recvEvents;
+
+ // Get our xmitCredit if it was sent
+ bool dataPresent = true;
+ if (e.immPresent() ) {
+ xmitCredit += (e.getImm() & ~FlagsMask);
+ dataPresent = ((e.getImm() & IgnoreData) == 0);
+ }
+
+ // if there was no data sent then the message was only to update our credit
+ if ( dataPresent ) {
+ readCallback(*this, b);
+ }
+
+ // At this point the buffer has been consumed so put it back on the recv queue
+ b->dataStart = 0;
+ b->dataCount = 0;
+ qp->postRecv(b);
+
+ // Received another message
+ ++recvCredit;
+
+ // Send recvCredit if it is large enough (it will have got this large because we've not sent anything recently)
+ if (recvCredit > recvBufferCount/2) {
+ // TODO: This should use RDMA write with imm as there might not ever be a buffer to receive this message
+ // but this is a little unlikely, as to get in this state we have to have received messages without sending any
+ // for a while so its likely we've received an credit update from the far side.
+ if (writable()) {
+ Buffer* ob = getBuffer();
+ // Have to send something as adapters hate it when you try to transfer 0 bytes
+ *reinterpret_cast< uint32_t* >(ob->bytes) = htonl(recvCredit);
+ ob->dataCount = sizeof(uint32_t);
+
+ int creditSent = recvCredit & ~FlagsMask;
+ qp->postSend(creditSent | IgnoreData, ob);
+ recvCredit -= creditSent;
+ ++outstandingWrites;
+ --xmitCredit;
+ } else {
+ QPID_LOG(warning, "RDMA: qp=" << qp << ": Unable to send unsolicited credit");
+ }
+ }
+ } else {
+ ++sendEvents;
+ {
+ qpid::sys::ScopedLock<qpid::sys::Mutex> l(bufferQueueLock);
+ bufferQueue.push_front(b);
+ }
+ --outstandingWrites;
+ }
+ } while (true);
+
+ // Not sure if this is expected or not
+ if (recvEvents == 0 && sendEvents == 0) {
+ QPID_LOG(debug, "RDMA: qp=" << qp << ": Got channel event with no recv/send completions");
+ }
+ }
+
+ void AsynchIO::doWriteCallback() {
+ // TODO: maybe don't call idle unless we're low on write buffers
+ // Keep on calling the idle routine as long as we are writable and we got something to write last call
+ while (writable()) {
+ int xc = xmitCredit;
+ idleCallback(*this);
+ // Check whether we actually wrote anything
+ if (xmitCredit == xc) {
+ QPID_LOG(debug, "RDMA: qp=" << qp << ": Called for data, but got none: xmitCredit=" << xmitCredit);
+ return;
+ }
+ }
+ }
+
+ Buffer* AsynchIO::getBuffer() {
+ qpid::sys::ScopedLock<qpid::sys::Mutex> l(bufferQueueLock);
+ assert(!bufferQueue.empty());
+ Buffer* b = bufferQueue.front();
+ bufferQueue.pop_front();
+ b->dataCount = 0;
+ b->dataStart = 0;
+ return b;
+ }
+
+ void AsynchIO::returnBuffer(Buffer* b) {
+ qpid::sys::ScopedLock<qpid::sys::Mutex> l(bufferQueueLock);
+ bufferQueue.push_front(b);
+ b->dataCount = 0;
+ b->dataStart = 0;
+ }
+
+ ConnectionManager::ConnectionManager(
+ ErrorCallback errc,
+ DisconnectedCallback dc
+ ) :
+ ci(Connection::make()),
+ handle(*ci, boost::bind(&ConnectionManager::event, this, _1), 0, 0),
+ errorCallback(errc),
+ disconnectedCallback(dc)
+ {
+ ci->nonblocking();
+ }
+
+ void ConnectionManager::start(Poller::shared_ptr poller) {
+ startConnection(ci);
+ handle.startWatch(poller);
+ }
+
+ void ConnectionManager::event(DispatchHandle&) {
+ connectionEvent(ci);
+ }
+
+ Listener::Listener(
+ const sockaddr& src,
+ const ConnectionParams& cp,
+ EstablishedCallback ec,
+ ErrorCallback errc,
+ DisconnectedCallback dc,
+ ConnectionRequestCallback crc
+ ) :
+ ConnectionManager(errc, dc),
+ src_addr(src),
+ checkConnectionParams(cp),
+ connectionRequestCallback(crc),
+ establishedCallback(ec)
+ {
+ }
+
+ void Listener::startConnection(Connection::intrusive_ptr ci) {
+ ci->bind(src_addr);
+ ci->listen();
+ }
+
+ void Listener::connectionEvent(Connection::intrusive_ptr ci) {
+ ConnectionEvent e(ci->getNextEvent());
+
+ // If (for whatever reason) there was no event do nothing
+ if (!e)
+ return;
+
+ // Important documentation ommision the new rdma_cm_id
+ // you get from CONNECT_REQUEST has the same context info
+ // as its parent listening rdma_cm_id
+ ::rdma_cm_event_type eventType = e.getEventType();
+ ::rdma_conn_param conn_param = e.getConnectionParam();
+ Rdma::Connection::intrusive_ptr id = e.getConnection();
+
+ switch (eventType) {
+ case RDMA_CM_EVENT_CONNECT_REQUEST: {
+ // Make sure peer has sent params we can use
+ if (!conn_param.private_data || conn_param.private_data_len < sizeof(ConnectionParams)) {
+ id->reject();
+ break;
+ }
+ ConnectionParams cp = *static_cast<const ConnectionParams*>(conn_param.private_data);
+
+ // Reject if requested msg size is bigger than we allow
+ if (cp.maxRecvBufferSize > checkConnectionParams.maxRecvBufferSize) {
+ id->reject(&checkConnectionParams);
+ break;
+ }
+
+ bool accept = true;
+ if (connectionRequestCallback)
+ accept = connectionRequestCallback(id, cp);
+
+ if (accept) {
+ // Accept connection
+ cp.initialXmitCredit = checkConnectionParams.initialXmitCredit;
+ id->accept(conn_param, &cp);
+ } else {
+ // Reject connection
+ id->reject();
+ }
+ break;
+ }
+ case RDMA_CM_EVENT_ESTABLISHED:
+ establishedCallback(id);
+ break;
+ case RDMA_CM_EVENT_DISCONNECTED:
+ disconnectedCallback(id);
+ break;
+ case RDMA_CM_EVENT_CONNECT_ERROR:
+ errorCallback(id, CONNECT_ERROR);
+ break;
+ default:
+ // Unexpected response
+ errorCallback(id, UNKNOWN);
+ //std::cerr << "Warning: unexpected response to listen - " << eventType << "\n";
+ }
+ }
+
+ Connector::Connector(
+ const sockaddr& dst,
+ const ConnectionParams& cp,
+ ConnectedCallback cc,
+ ErrorCallback errc,
+ DisconnectedCallback dc,
+ RejectedCallback rc
+ ) :
+ ConnectionManager(errc, dc),
+ dst_addr(dst),
+ connectionParams(cp),
+ rejectedCallback(rc),
+ connectedCallback(cc)
+ {
+ }
+
+ void Connector::startConnection(Connection::intrusive_ptr ci) {
+ ci->resolve_addr(dst_addr);
+ }
+
+ void Connector::connectionEvent(Connection::intrusive_ptr ci) {
+ ConnectionEvent e(ci->getNextEvent());
+
+ // If (for whatever reason) there was no event do nothing
+ if (!e)
+ return;
+
+ ::rdma_cm_event_type eventType = e.getEventType();
+ ::rdma_conn_param conn_param = e.getConnectionParam();
+ Rdma::Connection::intrusive_ptr id = e.getConnection();
+ switch (eventType) {
+ case RDMA_CM_EVENT_ADDR_RESOLVED:
+ // RESOLVE_ADDR
+ ci->resolve_route();
+ break;
+ case RDMA_CM_EVENT_ADDR_ERROR:
+ // RESOLVE_ADDR
+ errorCallback(ci, ADDR_ERROR);
+ break;
+ case RDMA_CM_EVENT_ROUTE_RESOLVED:
+ // RESOLVE_ROUTE:
+ ci->connect(&connectionParams);
+ break;
+ case RDMA_CM_EVENT_ROUTE_ERROR:
+ // RESOLVE_ROUTE:
+ errorCallback(ci, ROUTE_ERROR);
+ break;
+ case RDMA_CM_EVENT_CONNECT_ERROR:
+ // CONNECTING
+ errorCallback(ci, CONNECT_ERROR);
+ break;
+ case RDMA_CM_EVENT_UNREACHABLE:
+ // CONNECTING
+ errorCallback(ci, UNREACHABLE);
+ break;
+ case RDMA_CM_EVENT_REJECTED: {
+ // CONNECTING
+ // Extract private data from event
+ assert(conn_param.private_data && conn_param.private_data_len >= sizeof(ConnectionParams));
+ ConnectionParams cp = *static_cast<const ConnectionParams*>(conn_param.private_data);
+ rejectedCallback(ci, cp);
+ break;
+ }
+ case RDMA_CM_EVENT_ESTABLISHED: {
+ // CONNECTING
+ // Extract private data from event
+ assert(conn_param.private_data && conn_param.private_data_len >= sizeof(ConnectionParams));
+ ConnectionParams cp = *static_cast<const ConnectionParams*>(conn_param.private_data);
+ connectedCallback(ci, cp);
+ break;
+ }
+ case RDMA_CM_EVENT_DISCONNECTED:
+ // ESTABLISHED
+ disconnectedCallback(ci);
+ break;
+ default:
+ QPID_LOG(warning, "RDMA: Unexpected event in connect: " << eventType);
+ }
+ }
+}
diff --git a/RC9/qpid/cpp/src/qpid/sys/rdma/RdmaIO.h b/RC9/qpid/cpp/src/qpid/sys/rdma/RdmaIO.h
new file mode 100644
index 0000000000..577c22d053
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/rdma/RdmaIO.h
@@ -0,0 +1,222 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef Rdma_Acceptor_h
+#define Rdma_Acceptor_h
+
+#include "rdma_wrap.h"
+
+#include "qpid/sys/AtomicValue.h"
+#include "qpid/sys/Dispatcher.h"
+#include "qpid/sys/DispatchHandle.h"
+#include "qpid/sys/Mutex.h"
+
+#include <netinet/in.h>
+
+#include <boost/function.hpp>
+#include <boost/ptr_container/ptr_deque.hpp>
+#include <deque>
+
+namespace Rdma {
+
+ class Connection;
+
+ class AsynchIO
+ {
+ typedef boost::function1<void, AsynchIO&> ErrorCallback;
+ typedef boost::function2<void, AsynchIO&, Buffer*> ReadCallback;
+ typedef boost::function1<void, AsynchIO&> IdleCallback;
+ typedef boost::function2<void, AsynchIO&, Buffer*> FullCallback;
+
+ QueuePair::intrusive_ptr qp;
+ qpid::sys::DispatchHandleRef dataHandle;
+ int bufferSize;
+ int recvCredit;
+ int xmitCredit;
+ int recvBufferCount;
+ int xmitBufferCount;
+ int outstandingWrites;
+ bool closed; // TODO: Perhaps (probably) this state can be merged with the following...
+ bool deleting; // TODO: Perhaps (probably) this state can be merged with the following...
+ enum State { IDLE, DATA, PENDING_DATA, NOTIFY_WRITE, PENDING_NOTIFY, DELETED };
+ qpid::sys::AtomicValue<State> state;
+ //qpid::sys::Mutex stateLock;
+ std::deque<Buffer*> bufferQueue;
+ qpid::sys::Mutex bufferQueueLock;
+ boost::ptr_deque<Buffer> buffers;
+
+ ReadCallback readCallback;
+ IdleCallback idleCallback;
+ FullCallback fullCallback;
+ ErrorCallback errorCallback;
+
+ public:
+ // TODO: Instead of specifying a buffer size specify the amount of memory the AsynchIO class can use
+ // for buffers both read and write (allocate half to each up front) and fail if we cannot allocate that much
+ // locked memory
+ AsynchIO(
+ QueuePair::intrusive_ptr q,
+ int size,
+ int xCredit,
+ int rCount,
+ ReadCallback rc,
+ IdleCallback ic,
+ FullCallback fc,
+ ErrorCallback ec
+ );
+
+ void start(qpid::sys::Poller::shared_ptr poller);
+ bool writable() const;
+ bool bufferAvailable() const;
+ void queueWrite(Buffer* buff);
+ void notifyPendingWrite();
+ void queueWriteClose();
+ void deferDelete();
+ int incompletedWrites() const;
+ Buffer* getBuffer();
+ void returnBuffer(Buffer*);
+
+ private:
+ // Don't let anyone else delete us to make sure there can't be outstanding callbacks
+ ~AsynchIO();
+
+ // Constants for the peer-peer command messages
+ // These are sent in the high bits if the imm data of an rdma message
+ // The low bits are used to send the credit
+ const static int FlagsMask = 0x10000000; // Mask for all flag bits - be sure to update this if you add more command bits
+ const static int IgnoreData = 0x10000000; // Message contains no application data
+
+ void dataEvent(qpid::sys::DispatchHandle& handle);
+ void processCompletions();
+ void doWriteCallback();
+ };
+
+ inline bool AsynchIO::writable() const {
+ return (!closed && outstandingWrites < xmitBufferCount && xmitCredit > 0);
+ }
+
+ inline int AsynchIO::incompletedWrites() const {
+ return outstandingWrites;
+ }
+
+ inline bool AsynchIO::bufferAvailable() const {
+ return !bufferQueue.empty();
+ }
+ // These are the parameters necessary to start the conversation
+ // * Each peer HAS to allocate buffers of the size of the maximum receive from its peer
+ // * Each peer HAS to know the initial "credit" it has for transmitting to its peer
+ struct ConnectionParams {
+ int maxRecvBufferSize;
+ int initialXmitCredit ;
+
+ ConnectionParams(int s, int c) :
+ maxRecvBufferSize(s),
+ initialXmitCredit(c)
+ {}
+ };
+
+ enum ErrorType {
+ ADDR_ERROR,
+ ROUTE_ERROR,
+ CONNECT_ERROR,
+ UNREACHABLE,
+ UNKNOWN
+ };
+
+ typedef boost::function2<void, Rdma::Connection::intrusive_ptr&, ErrorType> ErrorCallback;
+ typedef boost::function1<void, Rdma::Connection::intrusive_ptr&> DisconnectedCallback;
+
+ class ConnectionManager {
+ Connection::intrusive_ptr ci;
+ qpid::sys::DispatchHandle handle;
+
+ protected:
+ ErrorCallback errorCallback;
+ DisconnectedCallback disconnectedCallback;
+
+ public:
+ ConnectionManager(
+ ErrorCallback errc,
+ DisconnectedCallback dc
+ );
+
+ virtual ~ConnectionManager() {}
+
+ void start(qpid::sys::Poller::shared_ptr poller);
+
+ private:
+ void event(qpid::sys::DispatchHandle& handle);
+
+ virtual void startConnection(Connection::intrusive_ptr ci) = 0;
+ virtual void connectionEvent(Connection::intrusive_ptr ci) = 0;
+ };
+
+ typedef boost::function2<bool, Rdma::Connection::intrusive_ptr&, const ConnectionParams&> ConnectionRequestCallback;
+ typedef boost::function1<void, Rdma::Connection::intrusive_ptr&> EstablishedCallback;
+
+ class Listener : public ConnectionManager
+ {
+ sockaddr src_addr;
+ ConnectionParams checkConnectionParams;
+ ConnectionRequestCallback connectionRequestCallback;
+ EstablishedCallback establishedCallback;
+
+ public:
+ Listener(
+ const sockaddr& src,
+ const ConnectionParams& cp,
+ EstablishedCallback ec,
+ ErrorCallback errc,
+ DisconnectedCallback dc,
+ ConnectionRequestCallback crc = 0
+ );
+
+ private:
+ void startConnection(Connection::intrusive_ptr ci);
+ void connectionEvent(Connection::intrusive_ptr ci);
+ };
+
+ typedef boost::function2<void, Rdma::Connection::intrusive_ptr&, const ConnectionParams&> RejectedCallback;
+ typedef boost::function2<void, Rdma::Connection::intrusive_ptr&, const ConnectionParams&> ConnectedCallback;
+
+ class Connector : public ConnectionManager
+ {
+ sockaddr dst_addr;
+ ConnectionParams connectionParams;
+ RejectedCallback rejectedCallback;
+ ConnectedCallback connectedCallback;
+
+ public:
+ Connector(
+ const sockaddr& dst,
+ const ConnectionParams& cp,
+ ConnectedCallback cc,
+ ErrorCallback errc,
+ DisconnectedCallback dc,
+ RejectedCallback rc = 0
+ );
+
+ private:
+ void startConnection(Connection::intrusive_ptr ci);
+ void connectionEvent(Connection::intrusive_ptr ci);
+ };
+}
+
+#endif // Rdma_Acceptor_h
diff --git a/RC9/qpid/cpp/src/qpid/sys/rdma/RdmaServer.cpp b/RC9/qpid/cpp/src/qpid/sys/rdma/RdmaServer.cpp
new file mode 100644
index 0000000000..594578a265
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/rdma/RdmaServer.cpp
@@ -0,0 +1,167 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "RdmaIO.h"
+
+#include <arpa/inet.h>
+
+#include <vector>
+#include <queue>
+#include <string>
+#include <iostream>
+
+#include <boost/bind.hpp>
+
+using std::vector;
+using std::queue;
+using std::string;
+using std::cout;
+using std::cerr;
+
+using qpid::sys::Poller;
+using qpid::sys::Dispatcher;
+
+// All the accepted connections
+struct ConRec {
+ Rdma::Connection::intrusive_ptr connection;
+ Rdma::AsynchIO* data;
+ queue<Rdma::Buffer*> queuedWrites;
+
+ ConRec(Rdma::Connection::intrusive_ptr c) :
+ connection(c)
+ {}
+};
+
+void dataError(Rdma::AsynchIO&) {
+ cout << "Data error:\n";
+}
+
+void idle(ConRec* cr, Rdma::AsynchIO& a) {
+ // Need to make sure full is not called as it would reorder messages
+ while (!cr->queuedWrites.empty() && a.writable()) {
+ Rdma::Buffer* buf = cr->queuedWrites.front();
+ cr->queuedWrites.pop();
+ a.queueWrite(buf);
+ }
+}
+
+void data(ConRec* cr, Rdma::AsynchIO& a, Rdma::Buffer* b) {
+ // Echo data back
+ Rdma::Buffer* buf = a.getBuffer();
+ std::copy(b->bytes+b->dataStart, b->bytes+b->dataStart+b->dataCount, buf->bytes);
+ buf->dataCount = b->dataCount;
+ if (cr->queuedWrites.empty()) {
+ // If can't write then full will be called and push buffer on back of queue
+ a.queueWrite(buf);
+ } else {
+ cr->queuedWrites.push(buf);
+ // Try to empty queue
+ idle(cr, a);
+ }
+}
+
+void full(ConRec* cr, Rdma::AsynchIO&, Rdma::Buffer* buf) {
+ cr->queuedWrites.push(buf);
+}
+
+void disconnected(Rdma::Connection::intrusive_ptr& ci) {
+ ConRec* cr = ci->getContext<ConRec>();
+ cr->connection->disconnect();
+ cr->data->queueWriteClose();
+ delete cr;
+ cout << "Disconnected: " << cr << "\n";
+}
+
+void connectionError(Rdma::Connection::intrusive_ptr& ci, Rdma::ErrorType) {
+ ConRec* cr = ci->getContext<ConRec>();
+ cr->connection->disconnect();
+ if (cr) {
+ cr->data->queueWriteClose();
+ delete cr;
+ }
+ cout << "Connection error: " << cr << "\n";
+}
+
+bool connectionRequest(Rdma::Connection::intrusive_ptr& ci, const Rdma::ConnectionParams& cp) {
+ cout << "Incoming connection: ";
+
+ // For fun reject alternate connection attempts
+ static bool x = false;
+ x = true;
+
+ // Must create aio here so as to prepost buffers *before* we accept connection
+ if (x) {
+ ConRec* cr = new ConRec(ci);
+ Rdma::AsynchIO* aio =
+ new Rdma::AsynchIO(ci->getQueuePair(),
+ cp.maxRecvBufferSize, cp.initialXmitCredit, Rdma::DEFAULT_WR_ENTRIES,
+ boost::bind(data, cr, _1, _2),
+ boost::bind(idle, cr, _1),
+ boost::bind(full, cr, _1, _2),
+ dataError);
+ ci->addContext(cr);
+ cr->data = aio;
+ cout << "Accept=>" << cr << "\n";
+ } else {
+ cout << "Reject\n";
+ }
+
+ return x;
+}
+
+void connected(Poller::shared_ptr poller, Rdma::Connection::intrusive_ptr& ci) {
+ static int cnt = 0;
+ ConRec* cr = ci->getContext<ConRec>();
+ cout << "Connected: " << cr << "(" << ++cnt << ")\n";
+
+ cr->data->start(poller);
+}
+
+int main(int argc, char* argv[]) {
+ vector<string> args(&argv[0], &argv[argc]);
+
+ ::sockaddr_in sin;
+
+ int port = (args.size() < 2) ? 20079 : atoi(args[1].c_str());
+ cout << "Listening on port: " << port << "\n";
+
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(port);
+ sin.sin_addr.s_addr = INADDR_ANY;
+
+ try {
+ boost::shared_ptr<Poller> p(new Poller());
+ Dispatcher d(p);
+
+ Rdma::Listener a((const sockaddr&)(sin),
+ Rdma::ConnectionParams(16384, Rdma::DEFAULT_WR_ENTRIES),
+ boost::bind(connected, p, _1),
+ connectionError,
+ disconnected,
+ connectionRequest);
+
+
+ a.start(p);
+ d.run();
+ } catch (Rdma::Exception& e) {
+ int err = e.getError();
+ cerr << "Error: " << e.what() << "(" << err << ")\n";
+ }
+}
diff --git a/RC9/qpid/cpp/src/qpid/sys/rdma/rdma_exception.h b/RC9/qpid/cpp/src/qpid/sys/rdma/rdma_exception.h
new file mode 100644
index 0000000000..7867aef2e4
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/rdma/rdma_exception.h
@@ -0,0 +1,65 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef RDMA_EXCEPTION_H
+#define RDMA_EXCEPTION_H
+
+#include <exception>
+
+#include <errno.h>
+#include <string.h>
+
+namespace Rdma {
+ static __thread char s[50];
+ class Exception : public std::exception {
+ int err;
+
+ public:
+ Exception(int e) : err(e) {}
+ int getError() { return err; }
+ const char* what() const throw() {
+ return ::strerror_r(err, s, 50);
+ }
+ };
+
+ inline void THROW_ERRNO() {
+ throw Rdma::Exception(errno);
+ }
+
+ inline void CHECK(int rc) {
+ if (rc != 0)
+ throw Rdma::Exception((rc == -1) ? errno : rc >0 ? rc : -rc);
+ }
+
+ inline void CHECK_IBV(int rc) {
+ if (rc != 0)
+ throw Rdma::Exception(rc);
+ }
+
+ template <typename T>
+ inline
+ T* CHECK_NULL(T* rc) {
+ if (rc == 0)
+ THROW_ERRNO();
+ return rc;
+ }
+}
+
+#endif // RDMA_EXCEPTION_H
diff --git a/RC9/qpid/cpp/src/qpid/sys/rdma/rdma_factories.cpp b/RC9/qpid/cpp/src/qpid/sys/rdma/rdma_factories.cpp
new file mode 100644
index 0000000000..c6e8df814b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/rdma/rdma_factories.cpp
@@ -0,0 +1,64 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "rdma_factories.h"
+
+namespace Rdma {
+ void acker(::rdma_cm_event* e) throw () {
+ if (e)
+ // Intentionally ignore return value - we can't do anything about it here
+ (void) ::rdma_ack_cm_event(e);
+ }
+
+ void destroyEChannel(::rdma_event_channel* c) throw () {
+ if (c)
+ // Intentionally ignore return value - we can't do anything about it here
+ (void) ::rdma_destroy_event_channel(c);
+ }
+
+ void destroyId(::rdma_cm_id* i) throw () {
+ if (i)
+ // Intentionally ignore return value - we can't do anything about it here
+ (void) ::rdma_destroy_id(i);
+ }
+
+ void deallocPd(::ibv_pd* p) throw () {
+ if (p)
+ // Intentionally ignore return value - we can't do anything about it here
+ (void) ::ibv_dealloc_pd(p);
+ }
+
+ void destroyCChannel(::ibv_comp_channel* c) throw () {
+ if (c)
+ // Intentionally ignore return value - we can't do anything about it here
+ (void) ::ibv_destroy_comp_channel(c);
+ }
+
+ void destroyCq(::ibv_cq* cq) throw () {
+ if (cq)
+ (void) ::ibv_destroy_cq(cq);
+ }
+
+ void destroyQp(::ibv_qp* qp) throw () {
+ if (qp)
+ (void) ::ibv_destroy_qp(qp);
+ }
+
+}
diff --git a/RC9/qpid/cpp/src/qpid/sys/rdma/rdma_factories.h b/RC9/qpid/cpp/src/qpid/sys/rdma/rdma_factories.h
new file mode 100644
index 0000000000..8d024f37aa
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/rdma/rdma_factories.h
@@ -0,0 +1,69 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef RDMA_FACTORIES_H
+#define RDMA_FACTORIES_H
+
+#include "rdma_exception.h"
+
+#include <rdma/rdma_cma.h>
+
+#include <boost/shared_ptr.hpp>
+
+namespace Rdma {
+ // These allow us to use simple shared_ptrs to do ref counting
+ void acker(::rdma_cm_event* e) throw ();
+ void destroyEChannel(::rdma_event_channel* c) throw ();
+ void destroyId(::rdma_cm_id* i) throw ();
+ void deallocPd(::ibv_pd* p) throw ();
+ void destroyCChannel(::ibv_comp_channel* c) throw ();
+ void destroyCq(::ibv_cq* cq) throw ();
+ void destroyQp(::ibv_qp* qp) throw ();
+
+ inline boost::shared_ptr< ::rdma_event_channel > mkEChannel() {
+ ::rdma_event_channel* c = CHECK_NULL(::rdma_create_event_channel());
+ return boost::shared_ptr< ::rdma_event_channel >(c, destroyEChannel);
+ }
+
+ inline boost::shared_ptr< ::rdma_cm_id >
+ mkId(::rdma_event_channel* ec, void* context, ::rdma_port_space ps) {
+ ::rdma_cm_id* i;
+ CHECK(::rdma_create_id(ec, &i, context, ps));
+ return boost::shared_ptr< ::rdma_cm_id >(i, destroyId);
+ }
+
+ inline boost::shared_ptr< ::ibv_pd > allocPd(::ibv_context* c) {
+ ::ibv_pd* pd = CHECK_NULL(ibv_alloc_pd(c));
+ return boost::shared_ptr< ::ibv_pd >(pd, deallocPd);
+ }
+
+ inline boost::shared_ptr< ::ibv_comp_channel > mkCChannel(::ibv_context* c) {
+ ::ibv_comp_channel* cc = CHECK_NULL(::ibv_create_comp_channel(c));
+ return boost::shared_ptr< ::ibv_comp_channel >(cc, destroyCChannel);
+ }
+
+ inline boost::shared_ptr< ::ibv_cq >
+ mkCq(::ibv_context* c, int cqe, void* context, ::ibv_comp_channel* cc) {
+ ::ibv_cq* cq = CHECK_NULL(ibv_create_cq(c, cqe, context, cc, 0));
+ return boost::shared_ptr< ::ibv_cq >(cq, destroyCq);
+ }
+}
+
+#endif // RDMA_FACTORIES_H
diff --git a/RC9/qpid/cpp/src/qpid/sys/rdma/rdma_wrap.cpp b/RC9/qpid/cpp/src/qpid/sys/rdma/rdma_wrap.cpp
new file mode 100644
index 0000000000..e105eb68c6
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/rdma/rdma_wrap.cpp
@@ -0,0 +1,183 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "rdma_wrap.h"
+
+namespace Rdma {
+ const ::rdma_conn_param DEFAULT_CONNECT_PARAM = {
+ 0, // .private_data
+ 0, // .private_data_len
+ 4, // .responder_resources
+ 4, // .initiator_depth
+ 0, // .flow_control
+ 5, // .retry_count
+ 7 // .rnr_retry_count
+ };
+
+ // This is moderately inefficient so don't use in a critical path
+ int deviceCount() {
+ int count;
+ ::ibv_free_device_list(::ibv_get_device_list(&count));
+ return count;
+ }
+
+ ::rdma_conn_param ConnectionEvent::getConnectionParam() const {
+ // It's badly documented, but it seems from the librdma source code that all the following
+ // event types have a valid param.conn
+ switch (event->event) {
+ case RDMA_CM_EVENT_CONNECT_REQUEST:
+ case RDMA_CM_EVENT_ESTABLISHED:
+ case RDMA_CM_EVENT_REJECTED:
+ case RDMA_CM_EVENT_DISCONNECTED:
+ case RDMA_CM_EVENT_CONNECT_ERROR:
+ return event->param.conn;
+ default:
+ ::rdma_conn_param p = {};
+ return p;
+ }
+ }
+
+ QueuePair::QueuePair(boost::shared_ptr< ::rdma_cm_id > i) :
+ qpid::sys::IOHandle(new qpid::sys::IOHandlePrivate),
+ pd(allocPd(i->verbs)),
+ cchannel(mkCChannel(i->verbs)),
+ scq(mkCq(i->verbs, DEFAULT_CQ_ENTRIES, 0, cchannel.get())),
+ rcq(mkCq(i->verbs, DEFAULT_CQ_ENTRIES, 0, cchannel.get())),
+ outstandingSendEvents(0),
+ outstandingRecvEvents(0)
+ {
+ impl->fd = cchannel->fd;
+
+ // Set cq context to this QueuePair object so we can find
+ // ourselves again
+ scq->cq_context = this;
+ rcq->cq_context = this;
+
+ ::ibv_qp_init_attr qp_attr = {};
+
+ // TODO: make a default struct for this
+ qp_attr.cap.max_send_wr = DEFAULT_WR_ENTRIES;
+ qp_attr.cap.max_send_sge = 4;
+ qp_attr.cap.max_recv_wr = DEFAULT_WR_ENTRIES;
+ qp_attr.cap.max_recv_sge = 4;
+
+ qp_attr.send_cq = scq.get();
+ qp_attr.recv_cq = rcq.get();
+ qp_attr.qp_type = IBV_QPT_RC;
+
+ CHECK(::rdma_create_qp(i.get(), pd.get(), &qp_attr));
+ qp = boost::shared_ptr< ::ibv_qp >(i->qp, destroyQp);
+
+ // Set the qp context to this so we can find ourselves again
+ qp->qp_context = this;
+ }
+
+ QueuePair::~QueuePair() {
+ if (outstandingSendEvents > 0)
+ ::ibv_ack_cq_events(scq.get(), outstandingSendEvents);
+ if (outstandingRecvEvents > 0)
+ ::ibv_ack_cq_events(rcq.get(), outstandingRecvEvents);
+
+ // Reset back pointer in case someone else has the qp
+ qp->qp_context = 0;
+ }
+
+ void QueuePair::postRecv(Buffer* buf) {
+ ::ibv_recv_wr rwr = {};
+ ::ibv_sge sge;
+
+ sge.addr = (uintptr_t) buf->bytes+buf->dataStart;
+ sge.length = buf->dataCount;
+ sge.lkey = buf->mr->lkey;
+
+ rwr.wr_id = reinterpret_cast<uint64_t>(buf);
+ rwr.sg_list = &sge;
+ rwr.num_sge = 1;
+
+ ::ibv_recv_wr* badrwr = 0;
+ CHECK_IBV(::ibv_post_recv(qp.get(), &rwr, &badrwr));
+ if (badrwr)
+ throw std::logic_error("ibv_post_recv(): Bad rwr");
+ }
+
+ void QueuePair::postSend(Buffer* buf) {
+ ::ibv_send_wr swr = {};
+ ::ibv_sge sge;
+
+ sge.addr = (uintptr_t) buf->bytes+buf->dataStart;
+ sge.length = buf->dataCount;
+ sge.lkey = buf->mr->lkey;
+
+ swr.wr_id = reinterpret_cast<uint64_t>(buf);
+ swr.opcode = IBV_WR_SEND;
+ swr.send_flags = IBV_SEND_SIGNALED;
+ swr.sg_list = &sge;
+ swr.num_sge = 1;
+
+ ::ibv_send_wr* badswr = 0;
+ CHECK_IBV(::ibv_post_send(qp.get(), &swr, &badswr));
+ if (badswr)
+ throw std::logic_error("ibv_post_send(): Bad swr");
+ }
+
+ void QueuePair::postSend(uint32_t imm, Buffer* buf) {
+ ::ibv_send_wr swr = {};
+ ::ibv_sge sge;
+
+ sge.addr = (uintptr_t) buf->bytes+buf->dataStart;
+ sge.length = buf->dataCount;
+ sge.lkey = buf->mr->lkey;
+ swr.send_flags = IBV_SEND_SIGNALED;
+
+ swr.wr_id = reinterpret_cast<uint64_t>(buf);
+ swr.imm_data = htonl(imm);
+ swr.opcode = IBV_WR_SEND_WITH_IMM;
+ swr.sg_list = &sge;
+ swr.num_sge = 1;
+
+ ::ibv_send_wr* badswr = 0;
+ CHECK_IBV(::ibv_post_send(qp.get(), &swr, &badswr));
+ if (badswr)
+ throw std::logic_error("ibv_post_send(): Bad swr");
+ }
+}
+
+std::ostream& operator<<(std::ostream& o, ::rdma_cm_event_type t) {
+# define CHECK_TYPE(t) case t: o << #t; break;
+ switch(t) {
+ CHECK_TYPE(RDMA_CM_EVENT_ADDR_RESOLVED)
+ CHECK_TYPE(RDMA_CM_EVENT_ADDR_ERROR)
+ CHECK_TYPE(RDMA_CM_EVENT_ROUTE_RESOLVED)
+ CHECK_TYPE(RDMA_CM_EVENT_ROUTE_ERROR)
+ CHECK_TYPE(RDMA_CM_EVENT_CONNECT_REQUEST)
+ CHECK_TYPE(RDMA_CM_EVENT_CONNECT_RESPONSE)
+ CHECK_TYPE(RDMA_CM_EVENT_CONNECT_ERROR)
+ CHECK_TYPE(RDMA_CM_EVENT_UNREACHABLE)
+ CHECK_TYPE(RDMA_CM_EVENT_REJECTED)
+ CHECK_TYPE(RDMA_CM_EVENT_ESTABLISHED)
+ CHECK_TYPE(RDMA_CM_EVENT_DISCONNECTED)
+ CHECK_TYPE(RDMA_CM_EVENT_DEVICE_REMOVAL)
+ CHECK_TYPE(RDMA_CM_EVENT_MULTICAST_JOIN)
+ CHECK_TYPE(RDMA_CM_EVENT_MULTICAST_ERROR)
+ }
+# undef CHECK_TYPE
+ return o;
+}
diff --git a/RC9/qpid/cpp/src/qpid/sys/rdma/rdma_wrap.h b/RC9/qpid/cpp/src/qpid/sys/rdma/rdma_wrap.h
new file mode 100644
index 0000000000..7812a02532
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/rdma/rdma_wrap.h
@@ -0,0 +1,498 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef RDMA_WRAP_H
+#define RDMA_WRAP_H
+
+#include "rdma_factories.h"
+
+#include <rdma/rdma_cma.h>
+
+#include "qpid/RefCounted.h"
+#include "qpid/sys/IOHandle.h"
+#include "qpid/sys/posix/PrivatePosix.h"
+
+#include <fcntl.h>
+
+#include <netdb.h>
+
+#include <vector>
+#include <algorithm>
+#include <iostream>
+#include <stdexcept>
+#include <boost/shared_ptr.hpp>
+#include <boost/intrusive_ptr.hpp>
+
+namespace Rdma {
+ const int DEFAULT_TIMEOUT = 2000; // 2 secs
+ const int DEFAULT_BACKLOG = 100;
+ const int DEFAULT_CQ_ENTRIES = 256;
+ const int DEFAULT_WR_ENTRIES = 64;
+ extern const ::rdma_conn_param DEFAULT_CONNECT_PARAM;
+
+ int deviceCount();
+
+ struct Buffer {
+ friend class QueuePair;
+
+ char* const bytes;
+ const int32_t byteCount;
+ int32_t dataStart;
+ int32_t dataCount;
+
+ Buffer(::ibv_pd* pd, char* const b, const int32_t s) :
+ bytes(b),
+ byteCount(s),
+ dataStart(0),
+ dataCount(0),
+ mr(CHECK_NULL(::ibv_reg_mr(
+ pd, bytes, byteCount,
+ ::IBV_ACCESS_LOCAL_WRITE)))
+ {}
+
+ ~Buffer() {
+ (void) ::ibv_dereg_mr(mr);
+ delete [] bytes;
+ }
+
+ private:
+ ::ibv_mr* mr;
+ };
+
+ class Connection;
+
+ enum QueueDirection {
+ NONE,
+ SEND,
+ RECV
+ };
+
+ class QueuePairEvent {
+ boost::shared_ptr< ::ibv_cq > cq;
+ ::ibv_wc wc;
+ QueueDirection dir;
+
+ friend class QueuePair;
+
+ QueuePairEvent() :
+ dir(NONE)
+ {}
+
+ QueuePairEvent(
+ const ::ibv_wc& w,
+ boost::shared_ptr< ::ibv_cq > c,
+ QueueDirection d) :
+ cq(c),
+ wc(w),
+ dir(d)
+ {
+ assert(dir != NONE);
+ }
+
+ public:
+ operator bool() const {
+ return dir != NONE;
+ }
+
+ bool immPresent() const {
+ return wc.wc_flags & IBV_WC_WITH_IMM;
+ }
+
+ uint32_t getImm() const {
+ return ntohl(wc.imm_data);
+ }
+
+ QueueDirection getDirection() const {
+ return dir;
+ }
+
+ ::ibv_wc_opcode getEventType() const {
+ return wc.opcode;
+ }
+
+ ::ibv_wc_status getEventStatus() const {
+ return wc.status;
+ }
+
+ Buffer* getBuffer() const {
+ Buffer* b = reinterpret_cast<Buffer*>(wc.wr_id);
+ b->dataCount = wc.byte_len;
+ return b;
+ }
+ };
+
+ // Wrapper for a queue pair - this has the functionality for
+ // putting buffers on the receive queue and for sending buffers
+ // to the other end of the connection.
+ class QueuePair : public qpid::sys::IOHandle, public qpid::RefCounted {
+ boost::shared_ptr< ::ibv_pd > pd;
+ boost::shared_ptr< ::ibv_comp_channel > cchannel;
+ boost::shared_ptr< ::ibv_cq > scq;
+ boost::shared_ptr< ::ibv_cq > rcq;
+ boost::shared_ptr< ::ibv_qp > qp;
+ int outstandingSendEvents;
+ int outstandingRecvEvents;
+
+ friend class Connection;
+
+ QueuePair(boost::shared_ptr< ::rdma_cm_id > id);
+ ~QueuePair();
+
+ public:
+ typedef boost::intrusive_ptr<QueuePair> intrusive_ptr;
+
+ // Create a buffer to use for writing
+ Buffer* createBuffer(int s) {
+ return new Buffer(pd.get(), new char[s], s);
+ }
+
+ // Make channel non-blocking by making
+ // associated fd nonblocking
+ void nonblocking() {
+ ::fcntl(cchannel->fd, F_SETFL, O_NONBLOCK);
+ }
+
+ // If we get EAGAIN because the channel has been set non blocking
+ // and we'd have to wait then return an empty event
+ QueuePair::intrusive_ptr getNextChannelEvent() {
+ // First find out which cq has the event
+ ::ibv_cq* cq;
+ void* ctx;
+ int rc = ::ibv_get_cq_event(cchannel.get(), &cq, &ctx);
+ if (rc == -1 && errno == EAGAIN)
+ return 0;
+ CHECK(rc);
+
+ // Batch acknowledge the event
+ if (cq == scq.get()) {
+ if (++outstandingSendEvents > DEFAULT_CQ_ENTRIES / 2) {
+ ::ibv_ack_cq_events(cq, outstandingSendEvents);
+ outstandingSendEvents = 0;
+ }
+ } else if (cq == rcq.get()) {
+ if (++outstandingRecvEvents > DEFAULT_CQ_ENTRIES / 2) {
+ ::ibv_ack_cq_events(cq, outstandingRecvEvents);
+ outstandingRecvEvents = 0;
+ }
+ }
+
+ return static_cast<QueuePair*>(ctx);
+ }
+
+ QueuePairEvent getNextEvent() {
+ ::ibv_wc w;
+ if (::ibv_poll_cq(scq.get(), 1, &w) == 1)
+ return QueuePairEvent(w, scq, SEND);
+ else if (::ibv_poll_cq(rcq.get(), 1, &w) == 1)
+ return QueuePairEvent(w, rcq, RECV);
+ else
+ return QueuePairEvent();
+ }
+
+ void postRecv(Buffer* buf);
+ void postSend(Buffer* buf);
+ void postSend(uint32_t imm, Buffer* buf);
+ void notifyRecv();
+ void notifySend();
+ };
+
+ class ConnectionEvent {
+ friend class Connection;
+
+ // The order of the members is important as we have to acknowledge
+ // the event before destroying the ids on destruction
+ boost::intrusive_ptr<Connection> id;
+ boost::intrusive_ptr<Connection> listen_id;
+ boost::shared_ptr< ::rdma_cm_event > event;
+
+ ConnectionEvent() {}
+ ConnectionEvent(::rdma_cm_event* e);
+
+ // Default copy, assignment and destructor ok
+ public:
+ operator bool() const {
+ return event;
+ }
+
+ ::rdma_cm_event_type getEventType() const {
+ return event->event;
+ }
+
+ ::rdma_conn_param getConnectionParam() const;
+
+ boost::intrusive_ptr<Connection> getConnection () const {
+ return id;
+ }
+
+ boost::intrusive_ptr<Connection> getListenId() const {
+ return listen_id;
+ }
+ };
+
+ // For the moment this is a fairly simple wrapper for rdma_cm_id.
+ //
+ // NB: It allocates a protection domain (pd) per connection which means that
+ // registered buffers can't be shared between different connections
+ // (this can only happen between connections on the same controller in any case,
+ // so needs careful management if used)
+ class Connection : public qpid::sys::IOHandle, public qpid::RefCounted {
+ boost::shared_ptr< ::rdma_event_channel > channel;
+ boost::shared_ptr< ::rdma_cm_id > id;
+ QueuePair::intrusive_ptr qp;
+
+ void* context;
+
+ friend class ConnectionEvent;
+ friend class QueuePair;
+
+ // Wrap the passed in rdma_cm_id with a Connection
+ // this basically happens only on connection request
+ Connection(::rdma_cm_id* i) :
+ qpid::sys::IOHandle(new qpid::sys::IOHandlePrivate),
+ id(i, destroyId),
+ context(0)
+ {
+ impl->fd = id->channel->fd;
+
+ // Just overwrite the previous context as it will
+ // have come from the listening connection
+ if (i)
+ i->context = this;
+ }
+
+ Connection() :
+ qpid::sys::IOHandle(new qpid::sys::IOHandlePrivate),
+ channel(mkEChannel()),
+ id(mkId(channel.get(), this, RDMA_PS_TCP)),
+ context(0)
+ {
+ impl->fd = channel->fd;
+ }
+
+ ~Connection() {
+ // Reset the id context in case someone else has it
+ id->context = 0;
+ }
+
+ // Default destructor fine
+
+ void ensureQueuePair() {
+ assert(id.get());
+
+ // Only allocate a queue pair if there isn't one already
+ if (qp)
+ return;
+
+ qp = new QueuePair(id);
+ }
+
+ public:
+ typedef boost::intrusive_ptr<Connection> intrusive_ptr;
+
+ static intrusive_ptr make() {
+ return new Connection();
+ }
+
+ static intrusive_ptr find(::rdma_cm_id* i) {
+ if (!i)
+ return 0;
+ Connection* id = static_cast< Connection* >(i->context);
+ if (!id)
+ throw std::logic_error("Couldn't find existing Connection");
+ return id;
+ }
+
+ template <typename T>
+ void addContext(T* c) {
+ // Don't allow replacing context
+ if (!context)
+ context = c;
+ }
+
+ template <typename T>
+ T* getContext() {
+ return static_cast<T*>(context);
+ }
+
+ // Make channel non-blocking by making
+ // associated fd nonblocking
+ void nonblocking() {
+ assert(id.get());
+ ::fcntl(id->channel->fd, F_SETFL, O_NONBLOCK);
+ }
+
+ // If we get EAGAIN because the channel has been set non blocking
+ // and we'd have to wait then return an empty event
+ ConnectionEvent getNextEvent() {
+ assert(id.get());
+ ::rdma_cm_event* e;
+ int rc = ::rdma_get_cm_event(id->channel, &e);
+ if (rc == -1 && errno == EAGAIN)
+ return ConnectionEvent();
+ CHECK(rc);
+ return ConnectionEvent(e);
+ }
+
+ void bind(sockaddr& src_addr) const {
+ assert(id.get());
+ CHECK(::rdma_bind_addr(id.get(), &src_addr));
+ }
+
+ void listen(int backlog = DEFAULT_BACKLOG) const {
+ assert(id.get());
+ CHECK(::rdma_listen(id.get(), backlog));
+ }
+
+ void resolve_addr(
+ sockaddr& dst_addr,
+ sockaddr* src_addr = 0,
+ int timeout_ms = DEFAULT_TIMEOUT) const
+ {
+ assert(id.get());
+ CHECK(::rdma_resolve_addr(id.get(), src_addr, &dst_addr, timeout_ms));
+ }
+
+ void resolve_route(int timeout_ms = DEFAULT_TIMEOUT) const {
+ assert(id.get());
+ CHECK(::rdma_resolve_route(id.get(), timeout_ms));
+ }
+
+ void disconnect() const {
+ assert(id.get());
+ CHECK(::rdma_disconnect(id.get()));
+ }
+
+ // TODO: Currently you can only connect with the default connection parameters
+ void connect() {
+ assert(id.get());
+
+ // Need to have a queue pair before we can connect
+ ensureQueuePair();
+
+ ::rdma_conn_param p = DEFAULT_CONNECT_PARAM;
+ CHECK(::rdma_connect(id.get(), &p));
+ }
+
+ template <typename T>
+ void connect(const T* data) {
+ assert(id.get());
+ // Need to have a queue pair before we can connect
+ ensureQueuePair();
+
+ ::rdma_conn_param p = DEFAULT_CONNECT_PARAM;
+ p.private_data = data;
+ p.private_data_len = sizeof(T);
+ CHECK(::rdma_connect(id.get(), &p));
+ }
+
+ // TODO: Not sure how to default accept params - they come from the connection request
+ // event
+ template <typename T>
+ void accept(const ::rdma_conn_param& param, const T* data) {
+ assert(id.get());
+ // Need to have a queue pair before we can accept
+ ensureQueuePair();
+
+ ::rdma_conn_param p = param;
+ p.private_data = data;
+ p.private_data_len = sizeof(T);
+ CHECK(::rdma_accept(id.get(), &p));
+ }
+
+ void accept(const ::rdma_conn_param& param) {
+ assert(id.get());
+ // Need to have a queue pair before we can accept
+ ensureQueuePair();
+
+ ::rdma_conn_param p = param;
+ p.private_data = 0;
+ p.private_data_len = 0;
+ CHECK(::rdma_accept(id.get(), &p));
+ }
+
+ template <typename T>
+ void reject(const T* data) const {
+ assert(id.get());
+ CHECK(::rdma_reject(id.get(), data, sizeof(T)));
+ }
+
+ void reject() const {
+ assert(id.get());
+ CHECK(::rdma_reject(id.get(), 0, 0));
+ }
+
+ QueuePair::intrusive_ptr getQueuePair() {
+ assert(id.get());
+
+ ensureQueuePair();
+
+ return qp;
+ }
+
+ std::string getLocalName() const {
+ ::sockaddr* addr = ::rdma_get_local_addr(id.get());
+ char hostName[NI_MAXHOST];
+ char portName[NI_MAXSERV];
+ CHECK_IBV(::getnameinfo(
+ addr, sizeof(::sockaddr_storage),
+ hostName, sizeof(hostName),
+ portName, sizeof(portName),
+ NI_NUMERICHOST | NI_NUMERICSERV));
+ std::string r(hostName);
+ r += ":";
+ r += portName;
+ return r;
+ }
+
+ std::string getPeerName() const {
+ ::sockaddr* addr = ::rdma_get_peer_addr(id.get());
+ char hostName[NI_MAXHOST];
+ char portName[NI_MAXSERV];
+ CHECK_IBV(::getnameinfo(
+ addr, sizeof(::sockaddr_storage),
+ hostName, sizeof(hostName),
+ portName, sizeof(portName),
+ NI_NUMERICHOST | NI_NUMERICSERV));
+ std::string r(hostName);
+ r += ":";
+ r += portName;
+ return r;
+ }
+ };
+
+ inline void QueuePair::notifyRecv() {
+ CHECK_IBV(ibv_req_notify_cq(rcq.get(), 0));
+ }
+
+ inline void QueuePair::notifySend() {
+ CHECK_IBV(ibv_req_notify_cq(scq.get(), 0));
+ }
+
+ inline ConnectionEvent::ConnectionEvent(::rdma_cm_event* e) :
+ id((e->event != RDMA_CM_EVENT_CONNECT_REQUEST) ?
+ Connection::find(e->id) : new Connection(e->id)),
+ listen_id(Connection::find(e->listen_id)),
+ event(e, acker)
+ {}
+}
+
+std::ostream& operator<<(std::ostream& o, ::rdma_cm_event_type t);
+
+#endif // RDMA_WRAP_H
diff --git a/RC9/qpid/cpp/src/qpid/sys/solaris/ECFPoller.cpp b/RC9/qpid/cpp/src/qpid/sys/solaris/ECFPoller.cpp
new file mode 100644
index 0000000000..783f84576b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/solaris/ECFPoller.cpp
@@ -0,0 +1,301 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/log/Logger.h"
+#include "qpid/sys/Poller.h"
+#include "qpid/sys/IOHandle.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/DeletionManager.h"
+#include "qpid/sys/posix/check.h"
+#include "qpid/sys/posix/PrivatePosix.h"
+
+#include <port.h>
+#include <poll.h>
+#include <errno.h>
+
+#include <assert.h>
+#include <vector>
+#include <exception>
+
+
+//TODO: Remove this
+#include "qpid/sys/Dispatcher.h"
+
+namespace qpid {
+namespace sys {
+
+// Deletion manager to handle deferring deletion of PollerHandles to when they definitely aren't being used
+DeletionManager<PollerHandle> PollerHandleDeletionManager;
+
+// Instantiate (and define) class static for DeletionManager
+template <>
+DeletionManager<PollerHandle>::AllThreadsStatuses DeletionManager<PollerHandle>::allThreadsStatuses(0);
+
+class PollerHandlePrivate {
+ friend class Poller;
+ friend class PollerHandle;
+
+ enum FDStat {
+ ABSENT,
+ MONITORED,
+ INACTIVE,
+ HUNGUP,
+ MONITORED_HUNGUP
+ };
+
+ int fd;
+ uint32_t events;
+ FDStat stat;
+ Mutex lock;
+
+ PollerHandlePrivate(int f) :
+ fd(f),
+ events(0),
+ stat(ABSENT) {
+ }
+
+ bool isActive() const {
+ return stat == MONITORED || stat == MONITORED_HUNGUP;
+ }
+
+ void setActive() {
+ stat = (stat == HUNGUP) ? MONITORED_HUNGUP : MONITORED;
+ }
+
+ bool isInactive() const {
+ return stat == INACTIVE || stat == HUNGUP;
+ }
+
+ void setInactive() {
+ stat = INACTIVE;
+ }
+
+ bool isIdle() const {
+ return stat == ABSENT;
+ }
+
+ void setIdle() {
+ stat = ABSENT;
+ }
+
+ bool isHungup() const {
+ return stat == MONITORED_HUNGUP || stat == HUNGUP;
+ }
+
+ void setHungup() {
+ assert(stat == MONITORED);
+ stat = HUNGUP;
+ }
+};
+
+PollerHandle::PollerHandle(const IOHandle& h) :
+ impl(new PollerHandlePrivate(toFd(h.impl)))
+{}
+
+PollerHandle::~PollerHandle() {
+ delete impl;
+}
+
+void PollerHandle::deferDelete() {
+ PollerHandleDeletionManager.markForDeletion(this);
+}
+
+/**
+ * Concrete implementation of Poller to use the Solaris Event Completion
+ * Framework interface
+ */
+class PollerPrivate {
+ friend class Poller;
+
+ const int portId;
+
+ static uint32_t directionToPollEvent(Poller::Direction dir) {
+ switch (dir) {
+ case Poller::INPUT: return POLLIN;
+ case Poller::OUTPUT: return POLLOUT;
+ case Poller::INOUT: return POLLIN | POLLOUT;
+ default: return 0;
+ }
+ }
+
+ static Poller::EventType pollToDirection(uint32_t events) {
+ uint32_t e = events & (POLLIN | POLLOUT);
+ switch (e) {
+ case POLLIN: return Poller::READABLE;
+ case POLLOUT: return Poller::WRITABLE;
+ case POLLIN | POLLOUT: return Poller::READ_WRITABLE;
+ default:
+ return (events & (POLLHUP | POLLERR)) ?
+ Poller::DISCONNECTED : Poller::INVALID;
+ }
+ }
+
+ PollerPrivate() :
+ portId(::port_create()) {
+ }
+
+ ~PollerPrivate() {
+ }
+};
+
+void Poller::addFd(PollerHandle& handle, Direction dir) {
+ PollerHandlePrivate& eh = *handle.impl;
+ ScopedLock<Mutex> l(eh.lock);
+
+ uint32_t events = 0;
+
+ if (eh.isIdle()) {
+ events = PollerPrivate::directionToPollEvent(dir);
+ } else {
+ assert(eh.isActive());
+ events = eh.events | PollerPrivate::directionToPollEvent(dir);
+ }
+
+ //port_associate can be used to add an association or modify an
+ //existing one
+ QPID_POSIX_CHECK(::port_associate(impl->portId, PORT_SOURCE_FD, (uintptr_t) eh.fd, events, &handle));
+ eh.events = events;
+ eh.setActive();
+ QPID_LOG(trace, "Poller::addFd(handle=" << &handle
+ << "[" << typeid(&handle).name()
+ << "], fd=" << eh.fd << ")");
+ //assert(dynamic_cast<DispatchHandle*>(&handle));
+}
+
+void Poller::delFd(PollerHandle& handle) {
+ PollerHandlePrivate& eh = *handle.impl;
+ ScopedLock<Mutex> l(eh.lock);
+ assert(!eh.isIdle());
+ int rc = ::port_dissociate(impl->portId, PORT_SOURCE_FD, (uintptr_t) eh.fd);
+ //Allow closing an invalid fd, allowing users to close fd before
+ //doing delFd()
+ if (rc == -1 && errno != EBADFD) {
+ QPID_POSIX_CHECK(rc);
+ }
+ eh.setIdle();
+ QPID_LOG(trace, "Poller::delFd(handle=" << &handle
+ << ", fd=" << eh.fd << ")");
+}
+
+// modFd is equivalent to delFd followed by addFd
+void Poller::modFd(PollerHandle& handle, Direction dir) {
+ PollerHandlePrivate& eh = *handle.impl;
+ ScopedLock<Mutex> l(eh.lock);
+ assert(!eh.isIdle());
+
+ eh.events = PollerPrivate::directionToPollEvent(dir);
+
+ //If fd is already associated, events and user arguments are updated
+ //So, no need to check if fd is already associated
+ QPID_POSIX_CHECK(::port_associate(impl->portId, PORT_SOURCE_FD, (uintptr_t) eh.fd, eh.events, &handle));
+ eh.setActive();
+ QPID_LOG(trace, "Poller::modFd(handle=" << &handle
+ << ", fd=" << eh.fd << ")");
+}
+
+void Poller::rearmFd(PollerHandle& handle) {
+ PollerHandlePrivate& eh = *handle.impl;
+ ScopedLock<Mutex> l(eh.lock);
+ assert(eh.isInactive());
+
+ QPID_POSIX_CHECK(::port_associate(impl->portId, PORT_SOURCE_FD, (uintptr_t) eh.fd, eh.events, &handle));
+ eh.setActive();
+ QPID_LOG(trace, "Poller::rearmdFd(handle=" << &handle
+ << ", fd=" << eh.fd << ")");
+}
+
+void Poller::shutdown() {
+ //Send an Alarm to the port
+ //We need to send a nonzero event mask, using POLLHUP, but
+ //The wait method will only look for a PORT_ALERT_SET
+ QPID_POSIX_CHECK(::port_alert(impl->portId, PORT_ALERT_SET, POLLHUP, NULL));
+ QPID_LOG(trace, "Poller::shutdown");
+}
+
+Poller::Event Poller::wait(Duration timeout) {
+ timespec_t tout;
+ timespec_t* ptout = NULL;
+ port_event_t pe;
+
+ if (timeout != TIME_INFINITE) {
+ tout.tv_sec = 0;
+ tout.tv_nsec = timeout;
+ ptout = &tout;
+ }
+
+ do {
+ PollerHandleDeletionManager.markAllUnusedInThisThread();
+ QPID_LOG(trace, "About to enter port_get. Thread "
+ << pthread_self()
+ << ", timeout=" << timeout);
+
+ int rc = ::port_get(impl->portId, &pe, ptout);
+
+ if (rc < 0) {
+ switch (errno) {
+ case EINTR:
+ continue;
+ case ETIME:
+ return Event(0, TIMEOUT);
+ default:
+ QPID_POSIX_CHECK(rc);
+ }
+ } else {
+ //We use alert mode to notify the shutdown of the Poller
+ if (pe.portev_source == PORT_SOURCE_ALERT) {
+ return Event(0, SHUTDOWN);
+ }
+ if (pe.portev_source == PORT_SOURCE_FD) {
+ PollerHandle *handle = static_cast<PollerHandle*>(pe.portev_user);
+ PollerHandlePrivate& eh = *handle->impl;
+ ScopedLock<Mutex> l(eh.lock);
+ QPID_LOG(trace, "About to send handle: " << handle);
+
+ if (eh.isActive()) {
+ if (pe.portev_events & POLLHUP) {
+ if (eh.isHungup()) {
+ return Event(handle, DISCONNECTED);
+ }
+ eh.setHungup();
+ } else {
+ eh.setInactive();
+ }
+ QPID_LOG(trace, "Sending event (thread: "
+ << pthread_self() << ") for handle " << handle
+ << ", direction= "
+ << PollerPrivate::pollToDirection(pe.portev_events));
+ return Event(handle, PollerPrivate::pollToDirection(pe.portev_events));
+ }
+ }
+ }
+ } while (true);
+}
+
+// Concrete constructors
+Poller::Poller() :
+ impl(new PollerPrivate())
+{}
+
+Poller::~Poller() {
+ delete impl;
+}
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/sys/ssl/SslHandler.cpp b/RC9/qpid/cpp/src/qpid/sys/ssl/SslHandler.cpp
new file mode 100644
index 0000000000..3c7e2190e7
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/ssl/SslHandler.cpp
@@ -0,0 +1,181 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "SslHandler.h"
+
+#include "SslIo.h"
+#include "SslSocket.h"
+#include "qpid/framing/AMQP_HighestVersion.h"
+#include "qpid/framing/ProtocolInitiation.h"
+#include "qpid/log/Statement.h"
+
+namespace qpid {
+namespace sys {
+namespace ssl {
+
+
+// Buffer definition
+struct Buff : public SslIO::BufferBase {
+ Buff() :
+ SslIO::BufferBase(new char[65536], 65536)
+ {}
+ ~Buff()
+ { delete [] bytes;}
+};
+
+SslHandler::SslHandler(std::string id, ConnectionCodec::Factory* f) :
+ identifier(id),
+ aio(0),
+ factory(f),
+ codec(0),
+ readError(false),
+ isClient(false)
+{}
+
+SslHandler::~SslHandler() {
+ if (codec)
+ codec->closed();
+ delete codec;
+}
+
+void SslHandler::init(SslIO* a, int numBuffs) {
+ aio = a;
+
+ // Give connection some buffers to use
+ for (int i = 0; i < numBuffs; i++) {
+ aio->queueReadBuffer(new Buff);
+ }
+}
+
+void SslHandler::write(const framing::ProtocolInitiation& data)
+{
+ QPID_LOG(debug, "SENT [" << identifier << "] INIT(" << data << ")");
+ SslIO::BufferBase* buff = aio->getQueuedBuffer();
+ if (!buff)
+ buff = new Buff;
+ framing::Buffer out(buff->bytes, buff->byteCount);
+ data.encode(out);
+ buff->dataCount = data.encodedSize();
+ aio->queueWrite(buff);
+}
+
+void SslHandler::activateOutput() {
+ aio->notifyPendingWrite();
+}
+
+void SslHandler::giveReadCredit(int32_t) {
+ // FIXME aconway 2008-12-05: not yet implemented.
+}
+
+// Input side
+void SslHandler::readbuff(SslIO& , SslIO::BufferBase* buff) {
+ if (readError) {
+ return;
+ }
+ size_t decoded = 0;
+ if (codec) { // Already initiated
+ try {
+ decoded = codec->decode(buff->bytes+buff->dataStart, buff->dataCount);
+ }catch(const std::exception& e){
+ QPID_LOG(error, e.what());
+ readError = true;
+ aio->queueWriteClose();
+ }
+ }else{
+ framing::Buffer in(buff->bytes+buff->dataStart, buff->dataCount);
+ framing::ProtocolInitiation protocolInit;
+ if (protocolInit.decode(in)) {
+ decoded = in.getPosition();
+ QPID_LOG(debug, "RECV [" << identifier << "] INIT(" << protocolInit << ")");
+ try {
+ codec = factory->create(protocolInit.getVersion(), *this, identifier);
+ if (!codec) {
+ //TODO: may still want to revise this...
+ //send valid version header & close connection.
+ write(framing::ProtocolInitiation(framing::highestProtocolVersion));
+ readError = true;
+ aio->queueWriteClose();
+ }
+ } catch (const std::exception& e) {
+ QPID_LOG(error, e.what());
+ readError = true;
+ aio->queueWriteClose();
+ }
+ }
+ }
+ // TODO: unreading needs to go away, and when we can cope
+ // with multiple sub-buffers in the general buffer scheme, it will
+ if (decoded != size_t(buff->dataCount)) {
+ // Adjust buffer for used bytes and then "unread them"
+ buff->dataStart += decoded;
+ buff->dataCount -= decoded;
+ aio->unread(buff);
+ } else {
+ // Give whole buffer back to aio subsystem
+ aio->queueReadBuffer(buff);
+ }
+}
+
+void SslHandler::eof(SslIO&) {
+ QPID_LOG(debug, "DISCONNECTED [" << identifier << "]");
+ if (codec) codec->closed();
+ aio->queueWriteClose();
+}
+
+void SslHandler::closedSocket(SslIO&, const SslSocket& s) {
+ // If we closed with data still to send log a warning
+ if (!aio->writeQueueEmpty()) {
+ QPID_LOG(warning, "CLOSING [" << identifier << "] unsent data (probably due to client disconnect)");
+ }
+ delete &s;
+ aio->queueForDeletion();
+ delete this;
+}
+
+void SslHandler::disconnect(SslIO& a) {
+ // treat the same as eof
+ eof(a);
+}
+
+// Notifications
+void SslHandler::nobuffs(SslIO&) {
+}
+
+void SslHandler::idle(SslIO&){
+ if (isClient && codec == 0) {
+ codec = factory->create(*this, identifier);
+ write(framing::ProtocolInitiation(codec->getVersion()));
+ return;
+ }
+ if (codec == 0) return;
+ if (codec->canEncode()) {
+ // Try and get a queued buffer if not then construct new one
+ SslIO::BufferBase* buff = aio->getQueuedBuffer();
+ if (!buff) buff = new Buff;
+ size_t encoded=codec->encode(buff->bytes, buff->byteCount);
+ buff->dataCount = encoded;
+ aio->queueWrite(buff);
+ }
+ if (codec->isClosed())
+ aio->queueWriteClose();
+}
+
+
+}}} // namespace qpid::sys::ssl
diff --git a/RC9/qpid/cpp/src/qpid/sys/ssl/SslHandler.h b/RC9/qpid/cpp/src/qpid/sys/ssl/SslHandler.h
new file mode 100644
index 0000000000..ae654d7ad2
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/ssl/SslHandler.h
@@ -0,0 +1,76 @@
+#ifndef QPID_SYS_SSL_SSLHANDLER_H
+#define QPID_SYS_SSL_SSLHANDLER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/ConnectionCodec.h"
+#include "qpid/sys/OutputControl.h"
+
+namespace qpid {
+
+namespace framing {
+ class ProtocolInitiation;
+}
+
+namespace sys {
+namespace ssl {
+
+class SslIO;
+class SslIOBufferBase;
+class SslSocket;
+
+class SslHandler : public OutputControl {
+ std::string identifier;
+ SslIO* aio;
+ ConnectionCodec::Factory* factory;
+ ConnectionCodec* codec;
+ bool readError;
+ bool isClient;
+
+ void write(const framing::ProtocolInitiation&);
+
+ public:
+ SslHandler(std::string id, ConnectionCodec::Factory* f);
+ ~SslHandler();
+ void init(SslIO* a, int numBuffs);
+
+ void setClient() { isClient = true; }
+
+ // Output side
+ void close();
+ void activateOutput();
+ void giveReadCredit(int32_t);
+
+ // Input side
+ void readbuff(SslIO& aio, SslIOBufferBase* buff);
+ void eof(SslIO& aio);
+ void disconnect(SslIO& aio);
+
+ // Notifications
+ void nobuffs(SslIO& aio);
+ void idle(SslIO& aio);
+ void closedSocket(SslIO& aio, const SslSocket& s);
+};
+
+}}} // namespace qpid::sys::ssl
+
+#endif /*!QPID_SYS_SSL_SSLHANDLER_H*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/ssl/SslIo.cpp b/RC9/qpid/cpp/src/qpid/sys/ssl/SslIo.cpp
new file mode 100644
index 0000000000..9be75af47d
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/ssl/SslIo.cpp
@@ -0,0 +1,433 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "SslIo.h"
+#include "SslSocket.h"
+
+#include "qpid/sys/Time.h"
+#include "qpid/sys/posix/check.h"
+#include "qpid/log/Statement.h"
+
+// TODO The basic algorithm here is not really POSIX specific and with a bit more abstraction
+// could (should) be promoted to be platform portable
+#include <unistd.h>
+#include <sys/socket.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+
+#include <boost/bind.hpp>
+
+using namespace qpid::sys;
+using namespace qpid::sys::ssl;
+
+namespace {
+
+/*
+ * Make *process* not generate SIGPIPE when writing to closed
+ * pipe/socket (necessary as default action is to terminate process)
+ */
+void ignoreSigpipe() {
+ ::signal(SIGPIPE, SIG_IGN);
+}
+
+/*
+ * We keep per thread state to avoid locking overhead. The assumption is that
+ * on average all the connections are serviced by all the threads so the state
+ * recorded in each thread is about the same. If this turns out not to be the
+ * case we could rebalance the info occasionally.
+ */
+__thread int threadReadTotal = 0;
+__thread int threadMaxRead = 0;
+__thread int threadReadCount = 0;
+__thread int threadWriteTotal = 0;
+__thread int threadWriteCount = 0;
+__thread int64_t threadMaxReadTimeNs = 2 * 1000000; // start at 2ms
+}
+
+/*
+ * Asynch Acceptor
+ */
+
+SslAcceptor::SslAcceptor(const SslSocket& s, Callback callback) :
+ acceptedCallback(callback),
+ handle(s, boost::bind(&SslAcceptor::readable, this, _1), 0, 0),
+ socket(s) {
+
+ s.setNonblocking();
+ ignoreSigpipe();
+}
+
+void SslAcceptor::start(Poller::shared_ptr poller) {
+ handle.startWatch(poller);
+}
+
+/*
+ * We keep on accepting as long as there is something to accept
+ */
+void SslAcceptor::readable(DispatchHandle& h) {
+ SslSocket* s;
+ do {
+ errno = 0;
+ // TODO: Currently we ignore the peers address, perhaps we should
+ // log it or use it for connection acceptance.
+ try {
+ s = socket.accept(0, 0);
+ if (s) {
+ acceptedCallback(*s);
+ } else {
+ break;
+ }
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Could not accept socket: " << e.what());
+ }
+ } while (true);
+
+ h.rewatch();
+}
+
+/*
+ * Asynch Connector
+ */
+
+SslConnector::SslConnector(const SslSocket& s,
+ Poller::shared_ptr poller,
+ std::string hostname,
+ uint16_t port,
+ ConnectedCallback connCb,
+ FailedCallback failCb) :
+ DispatchHandle(s,
+ 0,
+ boost::bind(&SslConnector::connComplete, this, _1),
+ boost::bind(&SslConnector::connComplete, this, _1)),
+ connCallback(connCb),
+ failCallback(failCb),
+ socket(s)
+{
+ //TODO: would be better for connect to be performed on a
+ //non-blocking socket, but that doesn't work at present so connect
+ //blocks until complete
+ try {
+ socket.connect(hostname, port);
+ socket.setNonblocking();
+ startWatch(poller);
+ } catch(std::exception& e) {
+ failure(-1, std::string(e.what()));
+ }
+}
+
+void SslConnector::connComplete(DispatchHandle& h)
+{
+ int errCode = socket.getError();
+
+ h.stopWatch();
+ if (errCode == 0) {
+ connCallback(socket);
+ DispatchHandle::doDelete();
+ } else {
+ // TODO: This need to be fixed as strerror isn't thread safe
+ failure(errCode, std::string(::strerror(errCode)));
+ }
+}
+
+void SslConnector::failure(int errCode, std::string message)
+{
+ if (failCallback)
+ failCallback(errCode, message);
+
+ socket.close();
+ delete &socket;
+
+ DispatchHandle::doDelete();
+}
+
+/*
+ * Asynch reader/writer
+ */
+SslIO::SslIO(const SslSocket& s,
+ ReadCallback rCb, EofCallback eofCb, DisconnectCallback disCb,
+ ClosedCallback cCb, BuffersEmptyCallback eCb, IdleCallback iCb) :
+
+ DispatchHandle(s,
+ boost::bind(&SslIO::readable, this, _1),
+ boost::bind(&SslIO::writeable, this, _1),
+ boost::bind(&SslIO::disconnected, this, _1)),
+ readCallback(rCb),
+ eofCallback(eofCb),
+ disCallback(disCb),
+ closedCallback(cCb),
+ emptyCallback(eCb),
+ idleCallback(iCb),
+ socket(s),
+ queuedClose(false),
+ writePending(false) {
+
+ s.setNonblocking();
+}
+
+struct deleter
+{
+ template <typename T>
+ void operator()(T *ptr){ delete ptr;}
+};
+
+SslIO::~SslIO() {
+ std::for_each( bufferQueue.begin(), bufferQueue.end(), deleter());
+ std::for_each( writeQueue.begin(), writeQueue.end(), deleter());
+}
+
+void SslIO::queueForDeletion() {
+ DispatchHandle::doDelete();
+}
+
+void SslIO::start(Poller::shared_ptr poller) {
+ DispatchHandle::startWatch(poller);
+}
+
+void SslIO::queueReadBuffer(BufferBase* buff) {
+ assert(buff);
+ buff->dataStart = 0;
+ buff->dataCount = 0;
+ bufferQueue.push_back(buff);
+ DispatchHandle::rewatchRead();
+}
+
+void SslIO::unread(BufferBase* buff) {
+ assert(buff);
+ if (buff->dataStart != 0) {
+ memmove(buff->bytes, buff->bytes+buff->dataStart, buff->dataCount);
+ buff->dataStart = 0;
+ }
+ bufferQueue.push_front(buff);
+ DispatchHandle::rewatchRead();
+}
+
+void SslIO::queueWrite(BufferBase* buff) {
+ assert(buff);
+ // If we've already closed the socket then throw the write away
+ if (queuedClose) {
+ bufferQueue.push_front(buff);
+ return;
+ } else {
+ writeQueue.push_front(buff);
+ }
+ writePending = false;
+ DispatchHandle::rewatchWrite();
+}
+
+void SslIO::notifyPendingWrite() {
+ writePending = true;
+ DispatchHandle::rewatchWrite();
+}
+
+void SslIO::queueWriteClose() {
+ queuedClose = true;
+ DispatchHandle::rewatchWrite();
+}
+
+/** Return a queued buffer if there are enough
+ * to spare
+ */
+SslIO::BufferBase* SslIO::getQueuedBuffer() {
+ // Always keep at least one buffer (it might have data that was "unread" in it)
+ if (bufferQueue.size()<=1)
+ return 0;
+ BufferBase* buff = bufferQueue.back();
+ assert(buff);
+ buff->dataStart = 0;
+ buff->dataCount = 0;
+ bufferQueue.pop_back();
+ return buff;
+}
+
+/*
+ * We keep on reading as long as we have something to read and a buffer to put
+ * it in
+ */
+void SslIO::readable(DispatchHandle& h) {
+ int readTotal = 0;
+ AbsTime readStartTime = AbsTime::now();
+ do {
+ // (Try to) get a buffer
+ if (!bufferQueue.empty()) {
+ // Read into buffer
+ BufferBase* buff = bufferQueue.front();
+ assert(buff);
+ bufferQueue.pop_front();
+ errno = 0;
+ int readCount = buff->byteCount-buff->dataCount;
+ int rc = socket.read(buff->bytes + buff->dataCount, readCount);
+ if (rc > 0) {
+ buff->dataCount += rc;
+ threadReadTotal += rc;
+ readTotal += rc;
+
+ readCallback(*this, buff);
+ if (rc != readCount) {
+ // If we didn't fill the read buffer then time to stop reading
+ break;
+ }
+
+ // Stop reading if we've overrun our timeslot
+ if (Duration(readStartTime, AbsTime::now()) > threadMaxReadTimeNs) {
+ break;
+ }
+
+ } else {
+ // Put buffer back (at front so it doesn't interfere with unread buffers)
+ bufferQueue.push_front(buff);
+ assert(buff);
+
+ // Eof or other side has gone away
+ if (rc == 0 || errno == ECONNRESET) {
+ eofCallback(*this);
+ h.unwatchRead();
+ break;
+ } else if (errno == EAGAIN) {
+ // We have just put a buffer back so we know
+ // we can carry on watching for reads
+ break;
+ } else {
+ // Report error then just treat as a socket disconnect
+ QPID_LOG(error, "Error reading socket: " << qpid::sys::strError(rc) << "(" << rc << ")" );
+ eofCallback(*this);
+ h.unwatchRead();
+ break;
+ }
+ }
+ } else {
+ // Something to read but no buffer
+ if (emptyCallback) {
+ emptyCallback(*this);
+ }
+ // If we still have no buffers we can't do anything more
+ if (bufferQueue.empty()) {
+ h.unwatchRead();
+ break;
+ }
+
+ }
+ } while (true);
+
+ ++threadReadCount;
+ threadMaxRead = std::max(threadMaxRead, readTotal);
+ return;
+}
+
+/*
+ * We carry on writing whilst we have data to write and we can write
+ */
+void SslIO::writeable(DispatchHandle& h) {
+ int writeTotal = 0;
+ do {
+ // See if we've got something to write
+ if (!writeQueue.empty()) {
+ // Write buffer
+ BufferBase* buff = writeQueue.back();
+ writeQueue.pop_back();
+ errno = 0;
+ assert(buff->dataStart+buff->dataCount <= buff->byteCount);
+ int rc = socket.write(buff->bytes+buff->dataStart, buff->dataCount);
+ if (rc >= 0) {
+ threadWriteTotal += rc;
+ writeTotal += rc;
+
+ // If we didn't write full buffer put rest back
+ if (rc != buff->dataCount) {
+ buff->dataStart += rc;
+ buff->dataCount -= rc;
+ writeQueue.push_back(buff);
+ break;
+ }
+
+ // Recycle the buffer
+ queueReadBuffer(buff);
+
+ // If we've already written more than the max for reading then stop
+ // (this is to stop writes dominating reads)
+ if (writeTotal > threadMaxRead)
+ break;
+ } else {
+ // Put buffer back
+ writeQueue.push_back(buff);
+ if (errno == ECONNRESET || errno == EPIPE) {
+ // Just stop watching for write here - we'll get a
+ // disconnect callback soon enough
+ h.unwatchWrite();
+ break;
+ } else if (errno == EAGAIN) {
+ // We have just put a buffer back so we know
+ // we can carry on watching for writes
+ break;
+ } else {
+ QPID_POSIX_CHECK(rc);
+ }
+ }
+ } else {
+ // If we're waiting to close the socket then can do it now as there is nothing to write
+ if (queuedClose) {
+ close(h);
+ break;
+ }
+ // Fd is writable, but nothing to write
+ if (idleCallback) {
+ writePending = false;
+ idleCallback(*this);
+ }
+ // If we still have no buffers to write we can't do anything more
+ if (writeQueue.empty() && !writePending && !queuedClose) {
+ h.unwatchWrite();
+ // The following handles the case where writePending is
+ // set to true after the test above; in this case its
+ // possible that the unwatchWrite overwrites the
+ // desired rewatchWrite so we correct that here
+ if (writePending)
+ h.rewatchWrite();
+ break;
+ }
+ }
+ } while (true);
+
+ ++threadWriteCount;
+ return;
+}
+
+void SslIO::disconnected(DispatchHandle& h) {
+ // If we've already queued close do it instead of disconnected callback
+ if (queuedClose) {
+ close(h);
+ } else if (disCallback) {
+ disCallback(*this);
+ h.unwatch();
+ }
+}
+
+/*
+ * Close the socket and callback to say we've done it
+ */
+void SslIO::close(DispatchHandle& h) {
+ h.stopWatch();
+ socket.close();
+ if (closedCallback) {
+ closedCallback(*this, socket);
+ }
+}
+
diff --git a/RC9/qpid/cpp/src/qpid/sys/ssl/SslIo.h b/RC9/qpid/cpp/src/qpid/sys/ssl/SslIo.h
new file mode 100644
index 0000000000..ba6483282b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/ssl/SslIo.h
@@ -0,0 +1,167 @@
+#ifndef _sys_ssl_SslIO
+#define _sys_ssl_SslIO
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/DispatchHandle.h"
+
+#include <boost/function.hpp>
+#include <deque>
+
+namespace qpid {
+namespace sys {
+namespace ssl {
+
+class SslSocket;
+
+/*
+ * Asynchronous ssl acceptor: accepts connections then does a callback
+ * with the accepted fd
+ */
+class SslAcceptor {
+public:
+ typedef boost::function1<void, const SslSocket&> Callback;
+
+private:
+ Callback acceptedCallback;
+ qpid::sys::DispatchHandle handle;
+ const SslSocket& socket;
+
+public:
+ SslAcceptor(const SslSocket& s, Callback callback);
+ void start(qpid::sys::Poller::shared_ptr poller);
+
+private:
+ void readable(qpid::sys::DispatchHandle& handle);
+};
+
+/*
+ * Asynchronous ssl connector: starts the process of initiating a
+ * connection and invokes a callback when completed or failed.
+ */
+class SslConnector : private qpid::sys::DispatchHandle {
+public:
+ typedef boost::function1<void, const SslSocket&> ConnectedCallback;
+ typedef boost::function2<void, int, std::string> FailedCallback;
+
+private:
+ ConnectedCallback connCallback;
+ FailedCallback failCallback;
+ const SslSocket& socket;
+
+public:
+ SslConnector(const SslSocket& socket,
+ Poller::shared_ptr poller,
+ std::string hostname,
+ uint16_t port,
+ ConnectedCallback connCb,
+ FailedCallback failCb = 0);
+
+private:
+ void connComplete(DispatchHandle& handle);
+ void failure(int, std::string);
+};
+
+struct SslIOBufferBase {
+ char* const bytes;
+ const int32_t byteCount;
+ int32_t dataStart;
+ int32_t dataCount;
+
+ SslIOBufferBase(char* const b, const int32_t s) :
+ bytes(b),
+ byteCount(s),
+ dataStart(0),
+ dataCount(0)
+ {}
+
+ virtual ~SslIOBufferBase()
+ {}
+};
+
+/*
+ * Asychronous reader/writer:
+ * Reader accepts buffers to read into; reads into the provided buffers
+ * and then does a callback with the buffer and amount read. Optionally it can callback
+ * when there is something to read but no buffer to read it into.
+ *
+ * Writer accepts a buffer and queues it for writing; can also be given
+ * a callback for when writing is "idle" (ie fd is writable, but nothing to write)
+ *
+ * The class is implemented in terms of DispatchHandle to allow it to be deleted by deleting
+ * the contained DispatchHandle
+ */
+class SslIO : private qpid::sys::DispatchHandle {
+public:
+ typedef SslIOBufferBase BufferBase;
+
+ typedef boost::function2<void, SslIO&, BufferBase*> ReadCallback;
+ typedef boost::function1<void, SslIO&> EofCallback;
+ typedef boost::function1<void, SslIO&> DisconnectCallback;
+ typedef boost::function2<void, SslIO&, const SslSocket&> ClosedCallback;
+ typedef boost::function1<void, SslIO&> BuffersEmptyCallback;
+ typedef boost::function1<void, SslIO&> IdleCallback;
+
+private:
+ ReadCallback readCallback;
+ EofCallback eofCallback;
+ DisconnectCallback disCallback;
+ ClosedCallback closedCallback;
+ BuffersEmptyCallback emptyCallback;
+ IdleCallback idleCallback;
+ const SslSocket& socket;
+ std::deque<BufferBase*> bufferQueue;
+ std::deque<BufferBase*> writeQueue;
+ bool queuedClose;
+ /**
+ * This flag is used to detect and handle concurrency between
+ * calls to notifyPendingWrite() (which can be made from any thread) and
+ * the execution of the writeable() method (which is always on the
+ * thread processing this handle.
+ */
+ volatile bool writePending;
+
+public:
+ SslIO(const SslSocket& s,
+ ReadCallback rCb, EofCallback eofCb, DisconnectCallback disCb,
+ ClosedCallback cCb = 0, BuffersEmptyCallback eCb = 0, IdleCallback iCb = 0);
+ void queueForDeletion();
+
+ void start(qpid::sys::Poller::shared_ptr poller);
+ void queueReadBuffer(BufferBase* buff);
+ void unread(BufferBase* buff);
+ void queueWrite(BufferBase* buff);
+ void notifyPendingWrite();
+ void queueWriteClose();
+ bool writeQueueEmpty() { return writeQueue.empty(); }
+ BufferBase* getQueuedBuffer();
+
+private:
+ ~SslIO();
+ void readable(qpid::sys::DispatchHandle& handle);
+ void writeable(qpid::sys::DispatchHandle& handle);
+ void disconnected(qpid::sys::DispatchHandle& handle);
+ void close(qpid::sys::DispatchHandle& handle);
+};
+
+}}}
+
+#endif // _sys_ssl_SslIO
diff --git a/RC9/qpid/cpp/src/qpid/sys/ssl/SslSocket.cpp b/RC9/qpid/cpp/src/qpid/sys/ssl/SslSocket.cpp
new file mode 100644
index 0000000000..597fbe57db
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/ssl/SslSocket.cpp
@@ -0,0 +1,279 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "SslSocket.h"
+#include "check.h"
+#include "util.h"
+#include "qpid/Exception.h"
+#include "qpid/sys/posix/check.h"
+#include "qpid/sys/posix/PrivatePosix.h"
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <cstdlib>
+#include <string.h>
+#include <iostream>
+
+#include <nspr4/private/pprio.h>
+#include <nss3/nss.h>
+#include <nss3/pk11pub.h>
+#include <nss3/ssl.h>
+#include <nss3/key.h>
+
+#include <boost/format.hpp>
+
+namespace qpid {
+namespace sys {
+namespace ssl {
+
+namespace {
+std::string getName(int fd, bool local, bool includeService = false)
+{
+ ::sockaddr_storage name; // big enough for any socket address
+ ::socklen_t namelen = sizeof(name);
+
+ int result = -1;
+ if (local) {
+ result = ::getsockname(fd, (::sockaddr*)&name, &namelen);
+ } else {
+ result = ::getpeername(fd, (::sockaddr*)&name, &namelen);
+ }
+
+ QPID_POSIX_CHECK(result);
+
+ char servName[NI_MAXSERV];
+ char dispName[NI_MAXHOST];
+ if (includeService) {
+ if (int rc=::getnameinfo((::sockaddr*)&name, namelen, dispName, sizeof(dispName),
+ servName, sizeof(servName),
+ NI_NUMERICHOST | NI_NUMERICSERV) != 0)
+ throw QPID_POSIX_ERROR(rc);
+ return std::string(dispName) + ":" + std::string(servName);
+
+ } else {
+ if (int rc=::getnameinfo((::sockaddr*)&name, namelen, dispName, sizeof(dispName), 0, 0, NI_NUMERICHOST) != 0)
+ throw QPID_POSIX_ERROR(rc);
+ return dispName;
+ }
+}
+
+std::string getService(int fd, bool local)
+{
+ ::sockaddr_storage name; // big enough for any socket address
+ ::socklen_t namelen = sizeof(name);
+
+ int result = -1;
+ if (local) {
+ result = ::getsockname(fd, (::sockaddr*)&name, &namelen);
+ } else {
+ result = ::getpeername(fd, (::sockaddr*)&name, &namelen);
+ }
+
+ QPID_POSIX_CHECK(result);
+
+ char servName[NI_MAXSERV];
+ if (int rc=::getnameinfo((::sockaddr*)&name, namelen, 0, 0,
+ servName, sizeof(servName),
+ NI_NUMERICHOST | NI_NUMERICSERV) != 0)
+ throw QPID_POSIX_ERROR(rc);
+ return servName;
+}
+
+}
+
+SslSocket::SslSocket() : IOHandle(new IOHandlePrivate()), socket(0), prototype(0)
+{
+ impl->fd = ::socket (PF_INET, SOCK_STREAM, 0);
+ if (impl->fd < 0) throw QPID_POSIX_ERROR(errno);
+ socket = SSL_ImportFD(0, PR_ImportTCPSocket(impl->fd));
+}
+
+/**
+ * This form of the constructor is used with the server-side sockets
+ * returned from accept. Because we use posix accept rather than
+ * PR_Accept, we have to reset the handshake.
+ */
+SslSocket::SslSocket(IOHandlePrivate* ioph, PRFileDesc* model) : IOHandle(ioph), socket(0), prototype(0)
+{
+ socket = SSL_ImportFD(model, PR_ImportTCPSocket(impl->fd));
+ NSS_CHECK(SSL_ResetHandshake(socket, true));
+ NSS_CHECK(SSL_ForceHandshake(socket));
+}
+
+void SslSocket::setNonblocking() const
+{
+ PRSocketOptionData option;
+ option.option = PR_SockOpt_Nonblocking;
+ option.value.non_blocking = true;
+ PR_SetSocketOption(socket, &option);
+}
+
+void SslSocket::connect(const std::string& host, uint16_t port) const
+{
+ std::stringstream namestream;
+ namestream << host << ":" << port;
+ connectname = namestream.str();
+
+ void* arg = SslOptions::global.certName.empty() ? 0 : const_cast<char*>(SslOptions::global.certName.c_str());
+ NSS_CHECK(SSL_GetClientAuthDataHook(socket, NSS_GetClientAuthData, arg));
+ NSS_CHECK(SSL_SetURL(socket, host.data()));
+
+ char hostBuffer[PR_NETDB_BUF_SIZE];
+ PRHostEnt hostEntry;
+ PR_CHECK(PR_GetHostByName(host.data(), hostBuffer, PR_NETDB_BUF_SIZE, &hostEntry));
+ PRNetAddr address;
+ int value = PR_EnumerateHostEnt(0, &hostEntry, port, &address);
+ if (value < 0) {
+ throw Exception(QPID_MSG("Error getting address for host: " << ErrorString()));
+ } else if (value == 0) {
+ throw Exception(QPID_MSG("Could not resolve address for host."));
+ }
+ PR_CHECK(PR_Connect(socket, &address, PR_INTERVAL_NO_TIMEOUT));
+ NSS_CHECK(SSL_ForceHandshake(socket));
+}
+
+void SslSocket::close() const
+{
+ if (impl->fd > 0) {
+ PR_Close(socket);
+ impl->fd = -1;
+ }
+}
+
+int SslSocket::listen(uint16_t port, int backlog, const std::string& certName, bool clientAuth) const
+{
+ //configure prototype socket:
+ prototype = SSL_ImportFD(0, PR_NewTCPSocket());
+ if (clientAuth) {
+ NSS_CHECK(SSL_OptionSet(prototype, SSL_REQUEST_CERTIFICATE, PR_TRUE));
+ NSS_CHECK(SSL_OptionSet(prototype, SSL_REQUIRE_CERTIFICATE, PR_TRUE));
+ }
+
+ //get certificate and key (is this the correct way?)
+ CERTCertificate *cert = PK11_FindCertFromNickname(const_cast<char*>(certName.c_str()), 0);
+ if (!cert) throw Exception(QPID_MSG("Failed to load certificate '" << certName << "'"));
+ SECKEYPrivateKey *key = PK11_FindKeyByAnyCert(cert, 0);
+ if (!key) throw Exception(QPID_MSG("Failed to retrieve private key from certificate"));
+ NSS_CHECK(SSL_ConfigSecureServer(prototype, cert, key, NSS_FindCertKEAType(cert)));
+ SECKEY_DestroyPrivateKey(key);
+ CERT_DestroyCertificate(cert);
+
+ //bind and listen
+ const int& socket = impl->fd;
+ int yes=1;
+ QPID_POSIX_CHECK(setsockopt(socket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes)));
+ struct sockaddr_in name;
+ name.sin_family = AF_INET;
+ name.sin_port = htons(port);
+ name.sin_addr.s_addr = 0;
+ if (::bind(socket, (struct sockaddr*)&name, sizeof(name)) < 0)
+ throw Exception(QPID_MSG("Can't bind to port " << port << ": " << strError(errno)));
+ if (::listen(socket, backlog) < 0)
+ throw Exception(QPID_MSG("Can't listen on port " << port << ": " << strError(errno)));
+
+ socklen_t namelen = sizeof(name);
+ if (::getsockname(socket, (struct sockaddr*)&name, &namelen) < 0)
+ throw QPID_POSIX_ERROR(errno);
+
+ return ntohs(name.sin_port);
+}
+
+SslSocket* SslSocket::accept(struct sockaddr *addr, socklen_t *addrlen) const
+{
+ int afd = ::accept(impl->fd, addr, addrlen);
+ if ( afd >= 0) {
+ return new SslSocket(new IOHandlePrivate(afd), prototype);
+ } else if (errno == EAGAIN) {
+ return 0;
+ } else {
+ throw QPID_POSIX_ERROR(errno);
+ }
+}
+
+int SslSocket::read(void *buf, size_t count) const
+{
+ return PR_Read(socket, buf, count);
+}
+
+int SslSocket::write(const void *buf, size_t count) const
+{
+ return PR_Write(socket, buf, count);
+}
+
+std::string SslSocket::getSockname() const
+{
+ return getName(impl->fd, true);
+}
+
+std::string SslSocket::getPeername() const
+{
+ return getName(impl->fd, false);
+}
+
+std::string SslSocket::getPeerAddress() const
+{
+ if (!connectname.empty())
+ return connectname;
+ return getName(impl->fd, false, true);
+}
+
+std::string SslSocket::getLocalAddress() const
+{
+ return getName(impl->fd, true, true);
+}
+
+uint16_t SslSocket::getLocalPort() const
+{
+ return std::atoi(getService(impl->fd, true).c_str());
+}
+
+uint16_t SslSocket::getRemotePort() const
+{
+ return atoi(getService(impl->fd, true).c_str());
+}
+
+int SslSocket::getError() const
+{
+ int result;
+ socklen_t rSize = sizeof (result);
+
+ if (::getsockopt(impl->fd, SOL_SOCKET, SO_ERROR, &result, &rSize) < 0)
+ throw QPID_POSIX_ERROR(errno);
+
+ return result;
+}
+
+void SslSocket::setTcpNoDelay(bool nodelay) const
+{
+ if (nodelay) {
+ PRSocketOptionData option;
+ option.option = PR_SockOpt_NoDelay;
+ option.value.no_delay = true;
+ PR_SetSocketOption(socket, &option);
+ }
+}
+
+}}} // namespace qpid::sys::ssl
diff --git a/RC9/qpid/cpp/src/qpid/sys/ssl/SslSocket.h b/RC9/qpid/cpp/src/qpid/sys/ssl/SslSocket.h
new file mode 100644
index 0000000000..a82e9133e8
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/ssl/SslSocket.h
@@ -0,0 +1,117 @@
+#ifndef _sys_ssl_Socket_h
+#define _sys_ssl_Socket_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/IOHandle.h"
+#include <nspr4/nspr.h>
+
+#include <string>
+
+struct sockaddr;
+
+namespace qpid {
+namespace sys {
+
+class Duration;
+
+namespace ssl {
+
+class SslSocket : public qpid::sys::IOHandle
+{
+public:
+ /** Create a socket wrapper for descriptor. */
+ SslSocket();
+
+ /** Set socket non blocking */
+ void setNonblocking() const;
+
+ /** Set tcp-nodelay */
+ void setTcpNoDelay(bool nodelay) const;
+
+ void connect(const std::string& host, uint16_t port) const;
+
+ void close() const;
+
+ /** Bind to a port and start listening.
+ *@param port 0 means choose an available port.
+ *@param backlog maximum number of pending connections.
+ *@param certName name of certificate to use to identify the server
+ *@return The bound port.
+ */
+ int listen(uint16_t port = 0, int backlog = 10, const std::string& certName = "localhost.localdomain", bool clientAuth = false) const;
+
+ /**
+ * Accept a connection from a socket that is already listening
+ * and has an incoming connection
+ */
+ SslSocket* accept(struct sockaddr *addr, socklen_t *addrlen) const;
+
+ // TODO The following are raw operations, maybe they need better wrapping?
+ int read(void *buf, size_t count) const;
+ int write(const void *buf, size_t count) const;
+
+ /** Returns the "socket name" ie the address bound to
+ * the near end of the socket
+ */
+ std::string getSockname() const;
+
+ /** Returns the "peer name" ie the address bound to
+ * the remote end of the socket
+ */
+ std::string getPeername() const;
+
+ /**
+ * Returns an address (host and port) for the remote end of the
+ * socket
+ */
+ std::string getPeerAddress() const;
+ /**
+ * Returns an address (host and port) for the local end of the
+ * socket
+ */
+ std::string getLocalAddress() const;
+
+ uint16_t getLocalPort() const;
+ uint16_t getRemotePort() const;
+
+ /**
+ * Returns the error code stored in the socket. This may be used
+ * to determine the result of a non-blocking connect.
+ */
+ int getError() const;
+
+private:
+ mutable std::string connectname;
+ mutable PRFileDesc* socket;
+ /**
+ * 'model' socket, with configuration to use when importing
+ * accepted sockets for use as ssl sockets. Set on listen(), used
+ * in accept to pass through to newly created socket instances.
+ */
+ mutable PRFileDesc* prototype;
+
+ SslSocket(IOHandlePrivate* ioph, PRFileDesc* model);
+};
+
+}}}
+#endif /*!_sys_ssl_Socket_h*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/ssl/check.cpp b/RC9/qpid/cpp/src/qpid/sys/ssl/check.cpp
new file mode 100644
index 0000000000..b580e9bcf5
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/ssl/check.cpp
@@ -0,0 +1,72 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "check.h"
+#include <nss3/secerr.h>
+#include <nss3/sslerr.h>
+#include <boost/format.hpp>
+
+using boost::format;
+using boost::str;
+
+namespace qpid {
+namespace sys {
+namespace ssl {
+
+const std::string SSL_ERROR_BAD_CERT_DOMAIN_STR =
+ "Unable to communicate securely with peer: requested domain name does not match the server's certificate.";
+const std::string SSL_ERROR_BAD_CERT_ALERT_STR = "SSL peer cannot verify your certificate.";
+const std::string SEC_ERROR_BAD_DATABASE_STR = "Security library: bad database.";
+const std::string SSL_ERROR_NO_CERTIFICATE_STR = "Unable to find the certificate or key necessary for authentication.";
+const std::string SSL_ERROR_UNKNOWN = "Unknown NSS error code.";
+
+ErrorString::ErrorString() : code(PR_GetError()), buffer(new char[PR_GetErrorTextLength()]), used(PR_GetErrorText(buffer)) {}
+
+ErrorString::~ErrorString()
+{
+ delete[] buffer;
+}
+
+std::string ErrorString::getString() const
+{
+ std::string msg = std::string(buffer, used);
+ if (!used) {
+ //seems most of the NSPR/NSS errors don't have text set for
+ //them, add a few specific ones in here. (TODO: more complete
+ //list?):
+ switch (code) {
+ case SSL_ERROR_BAD_CERT_DOMAIN: msg = SSL_ERROR_BAD_CERT_DOMAIN_STR; break;
+ case SSL_ERROR_BAD_CERT_ALERT: msg = SSL_ERROR_BAD_CERT_ALERT_STR; break;
+ case SEC_ERROR_BAD_DATABASE: msg = SEC_ERROR_BAD_DATABASE_STR; break;
+ case SSL_ERROR_NO_CERTIFICATE: msg = SSL_ERROR_NO_CERTIFICATE_STR; break;
+ default: msg = SSL_ERROR_UNKNOWN; break;
+ }
+ }
+ return str(format("%1% [%2%]") % msg % code);
+}
+
+std::ostream& operator<<(std::ostream& out, const ErrorString& err)
+{
+ out << err.getString();
+ return out;
+}
+
+
+}}} // namespace qpid::sys::ssl
diff --git a/RC9/qpid/cpp/src/qpid/sys/ssl/check.h b/RC9/qpid/cpp/src/qpid/sys/ssl/check.h
new file mode 100644
index 0000000000..6217a39429
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/ssl/check.h
@@ -0,0 +1,53 @@
+#ifndef QPID_SYS_SSL_CHECK_H
+#define QPID_SYS_SSL_CHECK_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <iostream>
+#include <string>
+#include <nspr4/nspr.h>
+#include <nss3/nss.h>
+
+namespace qpid {
+namespace sys {
+namespace ssl {
+
+class ErrorString
+{
+ public:
+ ErrorString();
+ ~ErrorString();
+ std::string getString() const;
+ private:
+ const int code;
+ char* const buffer;
+ const size_t used;
+};
+
+std::ostream& operator<<(std::ostream& out, const ErrorString& err);
+
+}}} // namespace qpid::sys::ssl
+
+
+#define NSS_CHECK(value) if (value != SECSuccess) { throw Exception(QPID_MSG("Failed: " << qpid::sys::ssl::ErrorString())); }
+#define PR_CHECK(value) if (value != PR_SUCCESS) { throw Exception(QPID_MSG("Failed: " << qpid::sys::ssl::ErrorString())); }
+
+#endif /*!QPID_SYS_SSL_CHECK_H*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/ssl/util.cpp b/RC9/qpid/cpp/src/qpid/sys/ssl/util.cpp
new file mode 100644
index 0000000000..97b00f19de
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/ssl/util.cpp
@@ -0,0 +1,118 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "util.h"
+#include "check.h"
+#include "qpid/Exception.h"
+#include "qpid/sys/SystemInfo.h"
+
+#include <unistd.h>
+#include <nspr4/nspr.h>
+#include <nss3/nss.h>
+#include <nss3/pk11pub.h>
+#include <nss3/ssl.h>
+
+#include <iostream>
+#include <fstream>
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+
+namespace qpid {
+namespace sys {
+namespace ssl {
+
+std::string defaultCertName()
+{
+ TcpAddress address;
+ if (SystemInfo::getLocalHostname(address)) {
+ return address.host;
+ } else {
+ return "localhost";
+ }
+}
+
+SslOptions::SslOptions() : qpid::Options("SSL Settings"),
+ certName(defaultCertName()),
+ exportPolicy(false)
+{
+ addOptions()
+ ("ssl-use-export-policy", optValue(exportPolicy), "Use NSS export policy")
+ ("ssl-cert-password-file", optValue(certPasswordFile, "PATH"), "File containing password to use for accessing certificate database")
+ ("ssl-cert-db", optValue(certDbPath, "PATH"), "Path to directory containing certificate database")
+ ("ssl-cert-name", optValue(certName, "NAME"), "Name of the certificate to use");
+}
+
+SslOptions& SslOptions::operator=(const SslOptions& o)
+{
+ certDbPath = o.certDbPath;
+ certName = o.certName;
+ certPasswordFile = o.certPasswordFile;
+ exportPolicy = o.exportPolicy;
+ return *this;
+}
+
+char* promptForPassword(PK11SlotInfo*, PRBool retry, void*)
+{
+ if (retry) return 0;
+ //TODO: something else?
+ return PL_strdup(getpass("Please enter the password for accessing the certificate database:"));
+}
+
+SslOptions SslOptions::global;
+
+char* readPasswordFromFile(PK11SlotInfo*, PRBool retry, void*)
+{
+ const std::string& passwordFile = SslOptions::global.certPasswordFile;
+ if (retry || passwordFile.empty() || !boost::filesystem::exists(passwordFile)) {
+ return 0;
+ } else {
+ std::ifstream file(passwordFile.c_str());
+ std::string password;
+ file >> password;
+ return PL_strdup(password.c_str());
+ }
+}
+
+void initNSS(const SslOptions& options, bool server)
+{
+ SslOptions::global = options;
+ if (options.certPasswordFile.empty()) {
+ PK11_SetPasswordFunc(promptForPassword);
+ } else {
+ PK11_SetPasswordFunc(readPasswordFromFile);
+ }
+ NSS_CHECK(NSS_Init(options.certDbPath.c_str()));
+ if (options.exportPolicy) {
+ NSS_CHECK(NSS_SetExportPolicy());
+ } else {
+ NSS_CHECK(NSS_SetDomesticPolicy());
+ }
+ if (server) {
+ //use defaults for all args, TODO: may want to make this configurable
+ SSL_ConfigServerSessionIDCache(0, 0, 0, 0);
+ }
+}
+
+void shutdownNSS()
+{
+ NSS_Shutdown();
+}
+
+}}} // namespace qpid::sys::ssl
diff --git a/RC9/qpid/cpp/src/qpid/sys/ssl/util.h b/RC9/qpid/cpp/src/qpid/sys/ssl/util.h
new file mode 100644
index 0000000000..f34adab7be
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/ssl/util.h
@@ -0,0 +1,50 @@
+#ifndef QPID_SYS_SSL_UTIL_H
+#define QPID_SYS_SSL_UTIL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/Options.h"
+#include <string>
+
+namespace qpid {
+namespace sys {
+namespace ssl {
+
+struct SslOptions : qpid::Options
+{
+ static SslOptions global;
+
+ std::string certDbPath;
+ std::string certName;
+ std::string certPasswordFile;
+ bool exportPolicy;
+
+ SslOptions();
+ SslOptions& operator=(const SslOptions&);
+};
+
+void initNSS(const SslOptions& options, bool server = false);
+void shutdownNSS();
+
+}}} // namespace qpid::sys::ssl
+
+#endif /*!QPID_SYS_SSL_UTIL_H*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/uuid.h b/RC9/qpid/cpp/src/qpid/sys/uuid.h
new file mode 100644
index 0000000000..804ab34463
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/uuid.h
@@ -0,0 +1,28 @@
+#ifndef _sys_uuid_h
+#define _sys_uuid_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifdef _WIN32
+# include "qpid/sys/windows/uuid.h"
+#else
+# include <uuid/uuid.h>
+#endif /* _WIN32 */
+
+#endif /* _sys_uuid_h */
diff --git a/RC9/qpid/cpp/src/qpid/sys/windows/AsynchIO.cpp b/RC9/qpid/cpp/src/qpid/sys/windows/AsynchIO.cpp
new file mode 100644
index 0000000000..ca56efd8dd
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/windows/AsynchIO.cpp
@@ -0,0 +1,741 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "AsynchIoResult.h"
+#include "IoHandlePrivate.h"
+#include "qpid/sys/AsynchIO.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Socket.h"
+#include "qpid/sys/Thread.h"
+#include "qpid/sys/Time.h"
+#include "qpid/log/Statement.h"
+
+#include "check.h"
+
+#include <boost/thread/once.hpp>
+
+#include <queue>
+#include <winsock2.h>
+#include <mswsock.h>
+#include <windows.h>
+
+#include <boost/bind.hpp>
+
+namespace {
+
+ typedef qpid::sys::ScopedLock<qpid::sys::Mutex> QLock;
+
+/*
+ * We keep per thread state to avoid locking overhead. The assumption is that
+ * on average all the connections are serviced by all the threads so the state
+ * recorded in each thread is about the same. If this turns out not to be the
+ * case we could rebalance the info occasionally.
+ */
+QPID_TSS int threadReadTotal = 0;
+QPID_TSS int threadMaxRead = 0;
+QPID_TSS int threadReadCount = 0;
+QPID_TSS int threadWriteTotal = 0;
+QPID_TSS int threadWriteCount = 0;
+QPID_TSS int64_t threadMaxReadTimeNs = 2 * 1000000; // start at 2ms
+
+/*
+ * The function pointers for AcceptEx and ConnectEx need to be looked up
+ * at run time. Make sure this is done only once.
+ */
+boost::once_flag lookUpAcceptExOnce = BOOST_ONCE_INIT;
+LPFN_ACCEPTEX fnAcceptEx = 0;
+typedef void (*lookUpFunc)(const qpid::sys::Socket &);
+
+void lookUpAcceptEx() {
+ SOCKET h = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ GUID guidAcceptEx = WSAID_ACCEPTEX;
+ DWORD dwBytes = 0;
+ WSAIoctl(h,
+ SIO_GET_EXTENSION_FUNCTION_POINTER,
+ &guidAcceptEx,
+ sizeof(guidAcceptEx),
+ &fnAcceptEx,
+ sizeof(fnAcceptEx),
+ &dwBytes,
+ NULL,
+ NULL);
+ closesocket(h);
+ if (fnAcceptEx == 0)
+ throw qpid::Exception(QPID_MSG("Failed to look up AcceptEx"));
+}
+
+}
+
+namespace qpid {
+namespace sys {
+
+/*
+ * Asynch Acceptor
+ *
+ * This implementation uses knowledge that the DispatchHandle handle member
+ * is derived from PollerHandle, which has a reference to the Socket.
+ * No dispatching features of DispatchHandle are used - we just use the
+ * conduit to the Socket.
+ *
+ * AsynchAcceptor uses an AsynchAcceptResult object to track completion
+ * and status of each accept operation outstanding.
+ */
+
+class AsynchAcceptorPrivate {
+
+ friend class AsynchAcceptResult;
+
+public:
+ AsynchAcceptorPrivate(const Socket& s, AsynchAcceptor::Callback callback);
+ ~AsynchAcceptorPrivate();
+ void start(Poller::shared_ptr poller);
+
+private:
+ void restart(void);
+
+ AsynchAcceptor::Callback acceptedCallback;
+ const Socket& socket;
+};
+
+AsynchAcceptor::AsynchAcceptor(const Socket& s, Callback callback) :
+ impl(new AsynchAcceptorPrivate(s, callback))
+{}
+
+AsynchAcceptor::~AsynchAcceptor()
+{ delete impl; }
+
+void AsynchAcceptor::start(Poller::shared_ptr poller) {
+ impl->start(poller);
+}
+
+AsynchAcceptorPrivate::AsynchAcceptorPrivate(const Socket& s,
+ AsynchAcceptor::Callback callback)
+ : acceptedCallback(callback),
+ socket(s) {
+
+ s.setNonblocking();
+#if (BOOST_VERSION >= 103500) /* boost 1.35 or later reversed the args */
+ boost::call_once(lookUpAcceptExOnce, lookUpAcceptEx);
+#else
+ boost::call_once(lookUpAcceptEx, lookUpAcceptExOnce);
+#endif
+}
+
+AsynchAcceptorPrivate::~AsynchAcceptorPrivate(void) {
+ socket.close();
+}
+
+void AsynchAcceptorPrivate::start(Poller::shared_ptr poller) {
+ poller->addFd(PollerHandle(socket), Poller::INPUT);
+ restart ();
+}
+
+void AsynchAcceptorPrivate::restart(void) {
+ DWORD bytesReceived = 0; // Not used, needed for AcceptEx API
+ AsynchAcceptResult *result = new AsynchAcceptResult(acceptedCallback,
+ this,
+ toFd(socket.impl));
+ BOOL status;
+ status = ::fnAcceptEx(toFd(socket.impl),
+ toFd(result->newSocket->impl),
+ result->addressBuffer,
+ 0,
+ AsynchAcceptResult::SOCKADDRMAXLEN,
+ AsynchAcceptResult::SOCKADDRMAXLEN,
+ &bytesReceived,
+ result->overlapped());
+ QPID_WINDOWS_CHECK_ASYNC_START(status);
+}
+
+
+AsynchAcceptResult::AsynchAcceptResult(AsynchAcceptor::Callback cb,
+ AsynchAcceptorPrivate *acceptor,
+ SOCKET listener)
+ : callback(cb), acceptor(acceptor), listener(listener) {
+ newSocket.reset (new Socket());
+}
+
+void AsynchAcceptResult::success(size_t /*bytesTransferred*/) {
+ ::setsockopt (toFd(newSocket->impl),
+ SOL_SOCKET,
+ SO_UPDATE_ACCEPT_CONTEXT,
+ (char*)&listener,
+ sizeof (listener));
+ callback(*(newSocket.release()));
+ acceptor->restart ();
+ delete this;
+}
+
+void AsynchAcceptResult::failure(int status) {
+ //if (status != WSA_OPERATION_ABORTED)
+ // Can there be anything else? ;
+ delete this;
+}
+
+namespace windows {
+
+/*
+ * AsynchConnector does synchronous connects for now... to do asynch the
+ * IocpPoller will need some extension to register an event handle as a
+ * CONNECT-type "direction", the connect completion/result will need an
+ * event handle to associate with the connecting handle. But there's no
+ * time for that right now...
+ */
+class AsynchConnector : public qpid::sys::AsynchConnector {
+private:
+ ConnectedCallback connCallback;
+ FailedCallback failCallback;
+ const Socket& socket;
+
+public:
+ AsynchConnector(const Socket& socket,
+ Poller::shared_ptr poller,
+ std::string hostname,
+ uint16_t port,
+ ConnectedCallback connCb,
+ FailedCallback failCb = 0);
+};
+
+AsynchConnector::AsynchConnector(const Socket& sock,
+ Poller::shared_ptr poller,
+ std::string hostname,
+ uint16_t port,
+ ConnectedCallback connCb,
+ FailedCallback failCb)
+ : connCallback(connCb), failCallback(failCb), socket(sock) {
+ socket.setNonblocking();
+ try {
+ socket.connect(hostname, port);
+ connCallback(socket);
+ } catch(std::exception& e) {
+ if (failCallback)
+ failCallback(-1, std::string(e.what()));
+ socket.close();
+ delete &socket;
+ }
+}
+
+} // namespace windows
+
+AsynchConnector* qpid::sys::AsynchConnector::create(const Socket& s,
+ Poller::shared_ptr poller,
+ std::string hostname,
+ uint16_t port,
+ ConnectedCallback connCb,
+ FailedCallback failCb)
+{
+ return new qpid::sys::windows::AsynchConnector(s,
+ poller,
+ hostname,
+ port,
+ connCb,
+ failCb);
+}
+
+
+/*
+ * Asynch reader/writer
+ */
+
+namespace windows {
+
+class AsynchIO : public qpid::sys::AsynchIO {
+public:
+ AsynchIO(const Socket& s,
+ ReadCallback rCb,
+ EofCallback eofCb,
+ DisconnectCallback disCb,
+ ClosedCallback cCb = 0,
+ BuffersEmptyCallback eCb = 0,
+ IdleCallback iCb = 0);
+ ~AsynchIO();
+
+ // Methods inherited from qpid::sys::AsynchIO
+
+ /**
+ * Notify the object is should delete itself as soon as possible.
+ */
+ virtual void queueForDeletion();
+
+ /// Take any actions needed to prepare for working with the poller.
+ virtual void start(Poller::shared_ptr poller);
+ virtual void queueReadBuffer(BufferBase* buff);
+ virtual void unread(BufferBase* buff);
+ virtual void queueWrite(BufferBase* buff);
+ virtual void notifyPendingWrite();
+ virtual void queueWriteClose();
+ virtual bool writeQueueEmpty();
+ virtual void startReading();
+
+ /**
+ * getQueuedBuffer returns a buffer from the buffer queue, if one is
+ * available.
+ *
+ * @retval Pointer to BufferBase buffer; 0 if none is available.
+ */
+ virtual BufferBase* getQueuedBuffer();
+
+private:
+ ReadCallback readCallback;
+ EofCallback eofCallback;
+ DisconnectCallback disCallback;
+ ClosedCallback closedCallback;
+ BuffersEmptyCallback emptyCallback;
+ IdleCallback idleCallback;
+ const Socket& socket;
+ Poller::shared_ptr poller;
+
+ std::deque<BufferBase*> bufferQueue;
+ std::deque<BufferBase*> writeQueue;
+ /* The MSVC-supplied deque is not thread-safe; keep locks to serialize
+ * access to the buffer queue and write queue.
+ */
+ Mutex bufferQueueLock;
+
+ // Number of outstanding I/O operations.
+ volatile LONG opsInProgress;
+ // Is there a write in progress?
+ volatile bool writeInProgress;
+ // Deletion requested, but there are callbacks in progress.
+ volatile bool queuedDelete;
+ // Socket close requested, but there are operations in progress.
+ volatile bool queuedClose;
+
+private:
+ // Dispatch events that have completed.
+ void notifyEof(void);
+ void notifyDisconnect(void);
+ void notifyClosed(void);
+ void notifyBuffersEmpty(void);
+ void notifyIdle(void);
+
+ /**
+ * Initiate a write of the specified buffer. There's no callback for
+ * write completion to the AsynchIO object.
+ */
+ void startWrite(AsynchIO::BufferBase* buff);
+
+ void close(void);
+
+ /**
+ * readComplete is called when a read request is complete.
+ *
+ * @param result Results of the operation.
+ */
+ void readComplete(AsynchReadResult *result);
+
+ /**
+ * writeComplete is called when a write request is complete.
+ *
+ * @param result Results of the operation.
+ */
+ void writeComplete(AsynchWriteResult *result);
+
+ /**
+ * Queue of completions to run. This queue enforces the requirement
+ * from upper layers that only one thread at a time is allowed to act
+ * on any given connection. Once a thread is busy processing a completion
+ * on this object, other threads that dispatch completions queue the
+ * completions here for the in-progress thread to handle when done.
+ * Thus, any threads can dispatch a completion from the IocpPoller, but
+ * this class ensures that actual processing at the connection level is
+ * only on one thread at a time.
+ */
+ std::queue<AsynchIoResult *> completionQueue;
+ volatile bool working;
+ Mutex completionLock;
+
+ /**
+ * Called when there's a completion to process.
+ */
+ void completion(AsynchIoResult *result);
+};
+
+AsynchIO::AsynchIO(const Socket& s,
+ ReadCallback rCb,
+ EofCallback eofCb,
+ DisconnectCallback disCb,
+ ClosedCallback cCb,
+ BuffersEmptyCallback eCb,
+ IdleCallback iCb) :
+
+ readCallback(rCb),
+ eofCallback(eofCb),
+ disCallback(disCb),
+ closedCallback(cCb),
+ emptyCallback(eCb),
+ idleCallback(iCb),
+ socket(s),
+ opsInProgress(0),
+ writeInProgress(false),
+ queuedDelete(false),
+ queuedClose(false),
+ working(false) {
+}
+
+struct deleter
+{
+ template <typename T>
+ void operator()(T *ptr){ delete ptr;}
+};
+
+AsynchIO::~AsynchIO() {
+ std::for_each( bufferQueue.begin(), bufferQueue.end(), deleter());
+ std::for_each( writeQueue.begin(), writeQueue.end(), deleter());
+}
+
+void AsynchIO::queueForDeletion() {
+ queuedDelete = true;
+ if (opsInProgress > 0) {
+ QPID_LOG(info, "Delete AsynchIO queued; ops in progress");
+ // AsynchIOHandler calls this then deletes itself; don't do any more
+ // callbacks.
+ readCallback = 0;
+ eofCallback = 0;
+ disCallback = 0;
+ closedCallback = 0;
+ emptyCallback = 0;
+ idleCallback = 0;
+ }
+ else {
+ delete this;
+ }
+}
+
+void AsynchIO::start(Poller::shared_ptr poller0) {
+ poller = poller0;
+ poller->addFd(PollerHandle(socket), Poller::INPUT);
+ if (writeQueue.size() > 0) // Already have data queued for write
+ notifyPendingWrite();
+ startReading();
+}
+
+void AsynchIO::queueReadBuffer(AsynchIO::BufferBase* buff) {
+ assert(buff);
+ buff->dataStart = 0;
+ buff->dataCount = 0;
+ QLock l(bufferQueueLock);
+ bufferQueue.push_back(buff);
+}
+
+void AsynchIO::unread(AsynchIO::BufferBase* buff) {
+ assert(buff);
+ if (buff->dataStart != 0) {
+ memmove(buff->bytes, buff->bytes+buff->dataStart, buff->dataCount);
+ buff->dataStart = 0;
+ }
+ QLock l(bufferQueueLock);
+ bufferQueue.push_front(buff);
+}
+
+void AsynchIO::queueWrite(AsynchIO::BufferBase* buff) {
+ assert(buff);
+ QLock l(bufferQueueLock);
+ writeQueue.push_back(buff);
+ if (!writeInProgress)
+ notifyPendingWrite();
+}
+
+void AsynchIO::notifyPendingWrite() {
+ // This method is generally called from a processing thread; transfer
+ // work on this to an I/O thread. Much of the upper layer code assumes
+ // that all I/O-related things happen in an I/O thread.
+ if (poller == 0) // Not really going yet...
+ return;
+
+ InterlockedIncrement(&opsInProgress);
+ IOHandlePrivate *hp =
+ new IOHandlePrivate (INVALID_SOCKET,
+ boost::bind(&AsynchIO::completion, this, _1));
+ IOHandle h(hp);
+ PollerHandle ph(h);
+ poller->addFd(ph, Poller::OUTPUT);
+}
+
+void AsynchIO::queueWriteClose() {
+ queuedClose = true;
+ if (!writeInProgress)
+ notifyPendingWrite();
+}
+
+bool AsynchIO::writeQueueEmpty() {
+ QLock l(bufferQueueLock);
+ return writeQueue.size() == 0;
+}
+
+/*
+ * Initiate a read operation. AsynchIO::readComplete() will be
+ * called when the read is complete and data is available.
+ */
+void AsynchIO::startReading() {
+ if (queuedDelete)
+ return;
+
+ // (Try to) get a buffer; look on the front since there may be an
+ // "unread" one there with data remaining from last time.
+ AsynchIO::BufferBase *buff = 0;
+ {
+ QLock l(bufferQueueLock);
+
+ if (!bufferQueue.empty()) {
+ buff = bufferQueue.front();
+ assert(buff);
+ bufferQueue.pop_front();
+ }
+ }
+ if (buff != 0) {
+ int readCount = buff->byteCount - buff->dataCount;
+ AsynchReadResult *result =
+ new AsynchReadResult(boost::bind(&AsynchIO::completion, this, _1),
+ buff,
+ readCount);
+ DWORD bytesReceived = 0, flags = 0;
+ InterlockedIncrement(&opsInProgress);
+ int status = WSARecv(toFd(socket.impl),
+ const_cast<LPWSABUF>(result->getWSABUF()), 1,
+ &bytesReceived,
+ &flags,
+ result->overlapped(),
+ 0);
+ if (status != 0) {
+ int error = WSAGetLastError();
+ if (error != WSA_IO_PENDING) {
+ result->failure(error);
+ result = 0; // result is invalid here
+ return;
+ }
+ }
+ // On status 0 or WSA_IO_PENDING, completion will handle the rest.
+ }
+ else {
+ notifyBuffersEmpty();
+ }
+ return;
+}
+
+/**
+ * Return a queued buffer if there are enough to spare.
+ */
+AsynchIO::BufferBase* AsynchIO::getQueuedBuffer() {
+ QLock l(bufferQueueLock);
+ // Always keep at least one buffer (it might have data that was
+ // "unread" in it).
+ if (bufferQueue.size() <= 1)
+ return 0;
+ BufferBase* buff = bufferQueue.back();
+ assert(buff);
+ bufferQueue.pop_back();
+ return buff;
+}
+
+void AsynchIO::notifyEof(void) {
+ if (eofCallback)
+ eofCallback(*this);
+}
+
+void AsynchIO::notifyDisconnect(void) {
+ if (disCallback)
+ disCallback(*this);
+}
+
+void AsynchIO::notifyClosed(void) {
+ if (closedCallback)
+ closedCallback(*this, socket);
+}
+
+void AsynchIO::notifyBuffersEmpty(void) {
+ if (emptyCallback)
+ emptyCallback(*this);
+}
+
+void AsynchIO::notifyIdle(void) {
+ if (idleCallback)
+ idleCallback(*this);
+}
+
+/*
+ * Asynch reader/writer using overlapped I/O
+ */
+
+void AsynchIO::startWrite(AsynchIO::BufferBase* buff) {
+ writeInProgress = true;
+ InterlockedIncrement(&opsInProgress);
+ int writeCount = buff->byteCount-buff->dataCount;
+ AsynchWriteResult *result =
+ new AsynchWriteResult(boost::bind(&AsynchIO::completion, this, _1),
+ buff,
+ buff->dataCount);
+ DWORD bytesSent = 0;
+ int status = WSASend(toFd(socket.impl),
+ const_cast<LPWSABUF>(result->getWSABUF()), 1,
+ &bytesSent,
+ 0,
+ result->overlapped(),
+ 0);
+ if (status != 0) {
+ int error = WSAGetLastError();
+ if (error != WSA_IO_PENDING) {
+ result->failure(error); // Also decrements in-progress count
+ result = 0; // result is invalid here
+ return;
+ }
+ }
+ // On status 0 or WSA_IO_PENDING, completion will handle the rest.
+ return;
+}
+
+/*
+ * Close the socket and callback to say we've done it
+ */
+void AsynchIO::close(void) {
+ socket.close();
+ notifyClosed();
+}
+
+void AsynchIO::readComplete(AsynchReadResult *result) {
+ ++threadReadCount;
+ int status = result->getStatus();
+ size_t bytes = result->getTransferred();
+ if (status == 0 && bytes > 0) {
+ bool restartRead = true; // May not if receiver doesn't want more
+ threadReadTotal += bytes;
+ if (readCallback)
+ restartRead = readCallback(*this, result->getBuff());
+ if (restartRead)
+ startReading();
+ }
+ else {
+ // No data read, so put the buffer back. It may be partially filled,
+ // so "unread" it back to the front of the queue.
+ unread(result->getBuff());
+ if (status == 0)
+ notifyEof();
+ else
+ notifyDisconnect();
+ }
+}
+
+/*
+ * NOTE - this completion is called for completed writes and also when
+ * a write is desired. The difference is in the buff - if a write is desired
+ * the buff is 0.
+ */
+void AsynchIO::writeComplete(AsynchWriteResult *result) {
+ int status = result->getStatus();
+ size_t bytes = result->getTransferred();
+ AsynchIO::BufferBase *buff = result->getBuff();
+ if (buff != 0) {
+ ++threadWriteCount;
+ writeInProgress = false;
+ if (status == 0 && bytes > 0) {
+ threadWriteTotal += bytes;
+ if (bytes < result->getRequested()) // Still more to go; resubmit
+ startWrite(buff);
+ else
+ queueReadBuffer(buff); // All done; back to the pool
+ }
+ else {
+ // An error... if it's a connection close, ignore it - it will be
+ // noticed and handled on a read completion any moment now.
+ // What to do with real error??? Save the Buffer?
+ }
+ }
+
+ // If there are no writes outstanding, the priority is to write any
+ // remaining buffers first (either queued or via idle), then close the
+ // socket if that's queued.
+ // opsInProgress handled in completion()
+ if (!writeInProgress) {
+ bool writing = false;
+ {
+ QLock l(bufferQueueLock);
+ if (writeQueue.size() > 0) {
+ buff = writeQueue.front();
+ assert(buff);
+ writeQueue.pop_front();
+ startWrite(buff);
+ writing = true;
+ }
+ }
+ if (!writing) {
+ if (queuedClose)
+ close();
+ else
+ notifyIdle();
+ }
+ }
+ return;
+}
+
+void AsynchIO::completion(AsynchIoResult *result) {
+ {
+ ScopedLock<Mutex> l(completionLock);
+ if (working) {
+ completionQueue.push(result);
+ return;
+ }
+
+ // First thread in with something to do; note we're working then keep
+ // handling completions.
+ working = true;
+ while (result != 0) {
+ // New scope to unlock temporarily.
+ {
+ ScopedUnlock<Mutex> ul(completionLock);
+ AsynchReadResult *r = dynamic_cast<AsynchReadResult*>(result);
+ if (r != 0)
+ readComplete(r);
+ else {
+ AsynchWriteResult *w =
+ dynamic_cast<AsynchWriteResult*>(result);
+ writeComplete(w);
+ }
+ delete result;
+ result = 0;
+ InterlockedDecrement(&opsInProgress);
+ }
+ // Lock is held again.
+ if (completionQueue.empty())
+ continue;
+ result = completionQueue.front();
+ completionQueue.pop();
+ }
+ working = false;
+ }
+ // Lock released; ok to delete if all is done.
+ if (opsInProgress == 0 && queuedDelete)
+ delete this;
+}
+
+} // namespace windows
+
+AsynchIO* qpid::sys::AsynchIO::create(const Socket& s,
+ AsynchIO::ReadCallback rCb,
+ AsynchIO::EofCallback eofCb,
+ AsynchIO::DisconnectCallback disCb,
+ AsynchIO::ClosedCallback cCb,
+ AsynchIO::BuffersEmptyCallback eCb,
+ AsynchIO::IdleCallback iCb)
+{
+ return new qpid::sys::windows::AsynchIO(s, rCb, eofCb, disCb, cCb, eCb, iCb);
+}
+
+}} // namespace qpid::sys
diff --git a/RC9/qpid/cpp/src/qpid/sys/windows/AsynchIoResult.h b/RC9/qpid/cpp/src/qpid/sys/windows/AsynchIoResult.h
new file mode 100755
index 0000000000..7db4e9c331
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/windows/AsynchIoResult.h
@@ -0,0 +1,185 @@
+#ifndef _windows_asynchIoResult_h
+#define _windows_asynchIoResult_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/AsynchIO.h"
+#include "qpid/sys/Socket.h"
+#include <memory.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+namespace qpid {
+namespace sys {
+
+/*
+ * AsynchIoResult defines the class that receives the result of an
+ * asynchronous I/O operation, either send/recv or accept/connect.
+ *
+ * Operation factories should set one of these up before beginning the
+ * operation. Poller knows how to dispatch completion to this class.
+ * This class must be subclassed for needed operations; this class provides
+ * an interface only and cannot be instantiated.
+ *
+ * This class is tied to Windows; it inherits from OVERLAPPED so that the
+ * IocpPoller can cast OVERLAPPED pointers back to AsynchIoResult and call
+ * the completion handler.
+ */
+class AsynchResult : private OVERLAPPED {
+public:
+ LPOVERLAPPED overlapped(void) { return this; }
+ static AsynchResult* from_overlapped(LPOVERLAPPED ol) {
+ return static_cast<AsynchResult*>(ol);
+ }
+ virtual void success (size_t bytesTransferred) {
+ bytes = bytesTransferred;
+ status = 0;
+ complete();
+ }
+ virtual void failure (int error) {
+ bytes = 0;
+ status = error;
+ complete();
+ }
+ size_t getTransferred(void) const { return bytes; }
+ int getStatus(void) const { return status; }
+
+protected:
+ AsynchResult() : bytes(0), status(0)
+ { memset(overlapped(), 0, sizeof(OVERLAPPED)); }
+ ~AsynchResult() {}
+ virtual void complete(void) = 0;
+
+ size_t bytes;
+ int status;
+};
+
+class AsynchAcceptorPrivate;
+class AsynchAcceptResult : public AsynchResult {
+
+ friend class AsynchAcceptorPrivate;
+
+public:
+ AsynchAcceptResult(AsynchAcceptor::Callback cb,
+ AsynchAcceptorPrivate *acceptor,
+ SOCKET listener);
+ virtual void success (size_t bytesTransferred);
+ virtual void failure (int error);
+
+private:
+ virtual void complete(void) {} // No-op for this class.
+
+ std::auto_ptr<qpid::sys::Socket> newSocket;
+ AsynchAcceptor::Callback callback;
+ AsynchAcceptorPrivate *acceptor;
+ SOCKET listener;
+
+ // AcceptEx needs a place to write the local and remote addresses
+ // when accepting the connection. Place those here; get enough for
+ // IPv6 addresses, even if the socket is IPv4.
+ enum { SOCKADDRMAXLEN = sizeof sockaddr_in6 + 16,
+ SOCKADDRBUFLEN = 2 * SOCKADDRMAXLEN };
+ char addressBuffer[SOCKADDRBUFLEN];
+};
+
+class AsynchIoResult : public AsynchResult {
+public:
+ typedef boost::function1<void, AsynchIoResult *> Completer;
+
+ virtual ~AsynchIoResult() {}
+ AsynchIO::BufferBase *getBuff(void) const { return iobuff; }
+ size_t getRequested(void) const { return requested; }
+ const WSABUF *getWSABUF(void) const { return &wsabuf; }
+
+protected:
+ void setBuff (AsynchIO::BufferBase *buffer) { iobuff = buffer; }
+
+protected:
+ AsynchIoResult(Completer cb,
+ AsynchIO::BufferBase *buff, size_t length)
+ : completionCallback(cb), iobuff(buff), requested(length) {}
+
+ virtual void complete(void) = 0;
+ WSABUF wsabuf;
+ Completer completionCallback;
+
+private:
+ AsynchIO::BufferBase *iobuff;
+ size_t requested; // Number of bytes in original I/O request
+};
+
+class AsynchReadResult : public AsynchIoResult {
+
+ // complete() updates buffer then does completion callback.
+ virtual void complete(void) {
+ getBuff()->dataCount += bytes;
+ completionCallback(this);
+ }
+
+public:
+ AsynchReadResult(AsynchIoResult::Completer cb,
+ AsynchIO::BufferBase *buff,
+ size_t length)
+ : AsynchIoResult(cb, buff, length) {
+ wsabuf.buf = buff->bytes + buff->dataCount;
+ wsabuf.len = length;
+ }
+};
+
+class AsynchWriteResult : public AsynchIoResult {
+
+ // complete() updates buffer then does completion callback.
+ virtual void complete(void) {
+ AsynchIO::BufferBase *b = getBuff();
+ b->dataStart += bytes;
+ b->dataCount -= bytes;
+ completionCallback(this);
+ }
+
+public:
+ AsynchWriteResult(AsynchIoResult::Completer cb,
+ AsynchIO::BufferBase *buff,
+ size_t length)
+ : AsynchIoResult(cb, buff, length) {
+ wsabuf.buf = buff ? buff->bytes : 0;
+ wsabuf.len = length;
+ }
+};
+
+class AsynchWriteWanted : public AsynchWriteResult {
+
+ // complete() just does completion callback; no buffers used.
+ virtual void complete(void) {
+ completionCallback(this);
+ }
+
+public:
+ AsynchWriteWanted(AsynchIoResult::Completer cb)
+ : AsynchWriteResult(cb, 0, 0) {
+ wsabuf.buf = 0;
+ wsabuf.len = 0;
+ }
+};
+
+}}
+
+#endif /*!_windows_asynchIoResult_h*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/windows/Condition.h b/RC9/qpid/cpp/src/qpid/sys/windows/Condition.h
new file mode 100755
index 0000000000..979fae9b0a
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/windows/Condition.h
@@ -0,0 +1,80 @@
+#ifndef _sys_windows_Condition_h
+#define _sys_windows_Condition_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Time.h"
+
+#include <time.h>
+#include <boost/noncopyable.hpp>
+#include <boost/thread/condition.hpp>
+#include <boost/thread/thread_time.hpp>
+#include <windows.h>
+
+namespace qpid {
+namespace sys {
+
+// Private Time related implementation details
+void toPtime(boost::posix_time::ptime& pt, const AbsTime& t);
+
+/**
+ * A condition variable for thread synchronization.
+ */
+class Condition : private boost::noncopyable
+{
+ public:
+ inline Condition();
+ inline ~Condition();
+ inline void wait(Mutex&);
+ inline bool wait(Mutex&, const AbsTime& absoluteTime);
+ inline void notify();
+ inline void notifyAll();
+
+ private:
+ boost::condition_variable_any condition;
+};
+
+Condition::Condition() {
+}
+
+Condition::~Condition() {
+}
+
+void Condition::wait(Mutex& mutex) {
+ condition.wait(mutex.mutex);
+}
+
+bool Condition::wait(Mutex& mutex, const AbsTime& absoluteTime){
+ return condition.timed_wait(mutex.mutex, absoluteTime.getPrivate());
+}
+
+void Condition::notify(){
+ condition.notify_one();
+}
+
+void Condition::notifyAll(){
+ condition.notify_all();
+}
+
+}}
+#endif /*!_sys_windows_Condition_h*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/windows/FileSysDir.cpp b/RC9/qpid/cpp/src/qpid/sys/windows/FileSysDir.cpp
new file mode 100644
index 0000000000..88f1637d48
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/windows/FileSysDir.cpp
@@ -0,0 +1,53 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/sys/FileSysDir.h"
+#include "qpid/sys/StrError.h"
+#include "qpid/Exception.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <direct.h>
+#include <errno.h>
+
+namespace qpid {
+namespace sys {
+
+bool FileSysDir::exists (void) const
+{
+ const char *cpath = dirPath.c_str ();
+ struct _stat s;
+ if (::_stat(cpath, &s)) {
+ if (errno == ENOENT) {
+ return false;
+ }
+ throw qpid::Exception (strError(errno) +
+ ": Can't check directory: " + dirPath);
+ }
+ if (s.st_mode & _S_IFDIR)
+ return true;
+ throw qpid::Exception(dirPath + " is not a directory");
+}
+
+void FileSysDir::mkdir(void)
+{
+ if (::_mkdir(dirPath.c_str()) == -1)
+ throw Exception ("Can't create directory: " + dirPath);
+}
+
+}} // namespace qpid::sys
diff --git a/RC9/qpid/cpp/src/qpid/sys/windows/IOHandle.cpp b/RC9/qpid/cpp/src/qpid/sys/windows/IOHandle.cpp
new file mode 100755
index 0000000000..ba544c8c90
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/windows/IOHandle.cpp
@@ -0,0 +1,42 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/IOHandle.h"
+#include "IoHandlePrivate.h"
+#include <windows.h>
+
+namespace qpid {
+namespace sys {
+
+SOCKET toFd(const IOHandlePrivate* h)
+{
+ return h->fd;
+}
+
+IOHandle::IOHandle(IOHandlePrivate* h) :
+ impl(h)
+{}
+
+IOHandle::~IOHandle() {
+ delete impl;
+}
+
+}} // namespace qpid::sys
diff --git a/RC9/qpid/cpp/src/qpid/sys/windows/IntegerTypes.h b/RC9/qpid/cpp/src/qpid/sys/windows/IntegerTypes.h
new file mode 100755
index 0000000000..80168fab88
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/windows/IntegerTypes.h
@@ -0,0 +1,40 @@
+#ifndef QPID_SYS_WINDOWS_INTEGERTYPES_H
+#define QPID_SYS_WINDOWS_INTEGERTYPES_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+typedef unsigned char uint8_t;
+typedef char int8_t;
+typedef unsigned short uint16_t;
+typedef short int16_t;
+typedef unsigned int uint32_t;
+typedef int int32_t;
+typedef unsigned __int64 uint64_t;
+typedef __int64 int64_t;
+
+// Visual Studio doesn't define other common types, so set them up here too.
+typedef int pid_t;
+typedef int socklen_t;
+typedef unsigned int size_t;
+typedef int ssize_t;
+typedef unsigned int uint;
+
+#endif /*!QPID_SYS_WINDOWS_INTEGERTYPES_H*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/windows/IoHandlePrivate.h b/RC9/qpid/cpp/src/qpid/sys/windows/IoHandlePrivate.h
new file mode 100755
index 0000000000..18e75047ed
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/windows/IoHandlePrivate.h
@@ -0,0 +1,52 @@
+#ifndef _sys_windows_IoHandlePrivate_h
+#define _sys_windows_IoHandlePrivate_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "AsynchIoResult.h"
+
+#include <winsock2.h>
+
+namespace qpid {
+namespace sys {
+
+// Private fd related implementation details
+// There should be either a valid socket handle or a completer callback.
+// Handle is used to associate with poller's iocp; completer is used to
+// inject a completion that will very quickly trigger a callback to the
+// completer from an I/O thread.
+class IOHandlePrivate {
+public:
+ IOHandlePrivate(SOCKET f = INVALID_SOCKET,
+ AsynchIoResult::Completer cb = 0) :
+ fd(f), event(cb)
+ {}
+
+ SOCKET fd;
+ AsynchIoResult::Completer event;
+};
+
+SOCKET toFd(const IOHandlePrivate* h);
+
+}}
+
+#endif /* _sys_windows_IoHandlePrivate_h */
diff --git a/RC9/qpid/cpp/src/qpid/sys/windows/IocpDispatcher.cpp b/RC9/qpid/cpp/src/qpid/sys/windows/IocpDispatcher.cpp
new file mode 100755
index 0000000000..1a0f6ce927
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/windows/IocpDispatcher.cpp
@@ -0,0 +1,54 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Dispatcher.h"
+
+#include <assert.h>
+
+namespace qpid {
+namespace sys {
+
+Dispatcher::Dispatcher(Poller::shared_ptr poller0) :
+ poller(poller0) {
+}
+
+Dispatcher::~Dispatcher() {
+}
+
+void Dispatcher::run() {
+ do {
+ Poller::Event event = poller->wait();
+
+ // Handle shutdown
+ switch (event.type) {
+ case Poller::SHUTDOWN:
+ return;
+ break;
+ case Poller::INVALID: // On any type of success or fail completion
+ break;
+ default:
+ // This should be impossible
+ assert(false);
+ }
+ } while (true);
+}
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/sys/windows/IocpPoller.cpp b/RC9/qpid/cpp/src/qpid/sys/windows/IocpPoller.cpp
new file mode 100755
index 0000000000..44298ac8ea
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/windows/IocpPoller.cpp
@@ -0,0 +1,176 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Poller.h"
+#include "qpid/sys/Mutex.h"
+
+#include "AsynchIoResult.h"
+#include "IoHandlePrivate.h"
+#include "check.h"
+
+#include <winsock2.h>
+#include <windows.h>
+
+#include <assert.h>
+#include <vector>
+#include <exception>
+
+namespace qpid {
+namespace sys {
+
+class PollerHandlePrivate {
+ friend class Poller;
+ friend class PollerHandle;
+
+ SOCKET fd;
+ AsynchIoResult::Completer cb;
+
+ PollerHandlePrivate(SOCKET f, AsynchIoResult::Completer cb0 = 0) :
+ fd(f), cb(cb0)
+ {
+ }
+
+};
+
+PollerHandle::PollerHandle(const IOHandle& h) :
+ impl(new PollerHandlePrivate(toFd(h.impl), h.impl->event))
+{}
+
+PollerHandle::~PollerHandle() {
+ delete impl;
+}
+
+/**
+ * Concrete implementation of Poller to use the Windows I/O Completion
+ * port (IOCP) facility.
+ */
+class PollerPrivate {
+ friend class Poller;
+
+ const HANDLE iocp;
+
+ // The number of threads running the event loop.
+ volatile LONG threadsRunning;
+
+ // Shutdown request is handled by setting isShutdown and injecting a
+ // well-formed completion event into the iocp.
+ bool isShutdown;
+
+ PollerPrivate() :
+ iocp(::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0)),
+ threadsRunning(0),
+ isShutdown(false) {
+ QPID_WINDOWS_CHECK_NULL(iocp);
+ }
+
+ ~PollerPrivate() {
+ // It's probably okay to ignore any errors here as there can't be
+ // data loss
+ ::CloseHandle(iocp);
+ }
+};
+
+void Poller::addFd(PollerHandle& handle, Direction dir) {
+ HANDLE h = (HANDLE)(handle.impl->fd);
+ if (h != INVALID_HANDLE_VALUE) {
+ HANDLE iocpHandle = ::CreateIoCompletionPort (h, impl->iocp, 0, 0);
+ QPID_WINDOWS_CHECK_NULL(iocpHandle);
+ }
+ else {
+ AsynchWriteWanted *result = new AsynchWriteWanted(handle.impl->cb);
+ PostQueuedCompletionStatus(impl->iocp, 0, 0, result->overlapped());
+ }
+}
+
+void Poller::shutdown() {
+ // Allow sloppy code to shut us down more than once.
+ if (impl->isShutdown)
+ return;
+ ULONG_PTR key = 1; // Tell wait() it's a shutdown, not I/O
+ PostQueuedCompletionStatus(impl->iocp, 0, key, 0);
+}
+
+// All no-ops...
+void Poller::delFd(PollerHandle& handle) {}
+void Poller::modFd(PollerHandle& handle, Direction dir) {}
+void Poller::rearmFd(PollerHandle& handle) {}
+
+Poller::Event Poller::wait(Duration timeout) {
+ DWORD timeoutMs = 0;
+ DWORD numTransferred = 0;
+ ULONG_PTR completionKey = 0;
+ OVERLAPPED *overlapped = 0;
+ AsynchResult *result = 0;
+
+ // Wait for either an I/O operation to finish (thus signaling the
+ // IOCP handle) or a shutdown request to be made (thus signaling the
+ // shutdown event).
+ if (timeout == TIME_INFINITE)
+ timeoutMs = INFINITE;
+ else
+ timeoutMs = static_cast<DWORD>(timeout / TIME_MSEC);
+
+ InterlockedIncrement(&impl->threadsRunning);
+ bool goodOp = ::GetQueuedCompletionStatus (impl->iocp,
+ &numTransferred,
+ &completionKey,
+ &overlapped,
+ timeoutMs);
+ LONG remainingThreads = InterlockedDecrement(&impl->threadsRunning);
+ if (goodOp) {
+ // Dequeued a successful completion. If it's a posted packet from
+ // shutdown() the overlapped ptr is 0 and key is 1. Else downcast
+ // the OVERLAPPED pointer to an AsynchIoResult and call the
+ // completion handler.
+ if (overlapped == 0 && completionKey == 1) {
+ // If there are other threads still running this wait, re-post
+ // the completion.
+ if (remainingThreads > 0)
+ PostQueuedCompletionStatus(impl->iocp, 0, completionKey, 0);
+ return Event(0, SHUTDOWN);
+ }
+
+ result = AsynchResult::from_overlapped(overlapped);
+ result->success (static_cast<size_t>(numTransferred));
+ }
+ else {
+ if (overlapped != 0) {
+ // Dequeued a completion for a failed operation. Downcast back
+ // to the result object and inform it that the operation failed.
+ DWORD status = ::GetLastError();
+ result = AsynchResult::from_overlapped(overlapped);
+ result->failure (static_cast<int>(status));
+ }
+ }
+ return Event(0, INVALID); // TODO - this may need to be changed.
+
+}
+
+// Concrete constructors
+Poller::Poller() :
+ impl(new PollerPrivate())
+{}
+
+Poller::~Poller() {
+ delete impl;
+}
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/sys/windows/LockFile.cpp b/RC9/qpid/cpp/src/qpid/sys/windows/LockFile.cpp
new file mode 100755
index 0000000000..9804020167
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/windows/LockFile.cpp
@@ -0,0 +1,83 @@
+/*
+ *
+ * Copyright (c) 2008 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/sys/LockFile.h"
+#include "check.h"
+
+#include <windows.h>
+
+namespace qpid {
+namespace sys {
+
+class LockFilePrivate {
+ friend class LockFile;
+
+ HANDLE fd;
+
+public:
+ LockFilePrivate(HANDLE f) : fd(f) {}
+};
+
+LockFile::LockFile(const std::string& path_, bool create)
+ : path(path_), created(create) {
+
+ HANDLE h = CreateFile(path.c_str(),
+ GENERIC_READ|GENERIC_WRITE,
+ 0, /* Disable opens by any other attempter */
+ 0, /* Default security */
+ OPEN_ALWAYS, /* Create if needed */
+ FILE_FLAG_DELETE_ON_CLOSE, /* Delete file when closed */
+ NULL);
+ QPID_WINDOWS_CHECK_NOT(h, INVALID_HANDLE_VALUE);
+ impl.reset(new LockFilePrivate(h));
+}
+
+LockFile::~LockFile() {
+ if (impl) {
+ if (impl->fd != INVALID_HANDLE_VALUE) {
+ CloseHandle(impl->fd);
+ }
+ }
+}
+
+pid_t LockFile::readPid(void) const {
+ if (!impl)
+ throw Exception("Lock file not open");
+
+ pid_t pid;
+ DWORD desired_read = sizeof(pid_t);
+ DWORD actual_read = 0;
+ if (!ReadFile(impl->fd, &pid, desired_read, &actual_read, 0)) {
+ throw Exception("Cannot read lock file " + path);
+ }
+ return pid;
+}
+
+void LockFile::writePid(void) {
+ if (!impl)
+ throw Exception("Lock file not open");
+
+ pid_t pid = GetCurrentProcessId();
+ DWORD desired_write = sizeof(pid_t);
+ DWORD written = 0;
+ if (!WriteFile(impl->fd, &pid, desired_write, &written, 0)) {
+ throw Exception("Cannot write lock file " + path);
+ }
+}
+
+}} /* namespace qpid::sys */
diff --git a/RC9/qpid/cpp/src/qpid/sys/windows/Mutex.h b/RC9/qpid/cpp/src/qpid/sys/windows/Mutex.h
new file mode 100755
index 0000000000..08de0712b9
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/windows/Mutex.h
@@ -0,0 +1,188 @@
+#ifndef _sys_windows_Mutex_h
+#define _sys_windows_Mutex_h
+
+/*
+ *
+ * Copyright (c) 2008 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "check.h"
+
+#include <boost/version.hpp>
+#if (BOOST_VERSION < 103500)
+#error The Windows port requires Boost version 1.35.0 or later
+#endif
+
+#include <boost/noncopyable.hpp>
+#include <boost/thread/recursive_mutex.hpp>
+#include <boost/thread/shared_mutex.hpp>
+#include <boost/thread/thread_time.hpp>
+#include <boost/thread/tss.hpp>
+
+namespace qpid {
+namespace sys {
+
+class Condition;
+
+/**
+ * Mutex lock.
+ */
+class Mutex : private boost::noncopyable {
+ friend class Condition;
+
+public:
+ typedef ::qpid::sys::ScopedLock<Mutex> ScopedLock;
+ typedef ::qpid::sys::ScopedUnlock<Mutex> ScopedUnlock;
+
+ inline Mutex();
+ inline ~Mutex();
+ inline void lock();
+ inline void unlock();
+ inline bool trylock();
+
+
+protected:
+ boost::recursive_mutex mutex;
+};
+
+/**
+ * RW lock.
+ */
+class RWlock : private boost::noncopyable {
+ friend class Condition;
+
+public:
+ typedef ::qpid::sys::ScopedRlock<RWlock> ScopedRlock;
+ typedef ::qpid::sys::ScopedWlock<RWlock> ScopedWlock;
+
+ inline RWlock();
+ inline ~RWlock();
+ inline void wlock(); // will write-lock
+ inline void rlock(); // will read-lock
+ inline void unlock();
+ inline void trywlock(); // will write-try
+ inline void tryrlock(); // will read-try
+
+protected:
+ boost::shared_mutex rwMutex;
+ boost::thread_specific_ptr<bool> haveWrite;
+
+ inline bool &write (void);
+};
+
+
+/**
+ * PODMutex is a POD, can be static-initialized with
+ * PODMutex m = QPID_PODMUTEX_INITIALIZER
+ */
+struct PODMutex
+{
+ typedef ::qpid::sys::ScopedLock<PODMutex> ScopedLock;
+
+ inline void lock();
+ inline void unlock();
+ inline bool trylock();
+
+ // Must be public to be a POD:
+ boost::recursive_mutex mutex;
+};
+
+#define QPID_MUTEX_INITIALIZER 0
+
+void PODMutex::lock() {
+ mutex.lock();
+}
+
+void PODMutex::unlock() {
+ mutex.unlock();
+}
+
+bool PODMutex::trylock() {
+ return mutex.try_lock();
+}
+
+Mutex::Mutex() {
+}
+
+Mutex::~Mutex(){
+}
+
+void Mutex::lock() {
+ mutex.lock();
+}
+
+void Mutex::unlock() {
+ mutex.unlock();
+}
+
+bool Mutex::trylock() {
+ return mutex.try_lock();
+}
+
+
+RWlock::RWlock() {
+}
+
+RWlock::~RWlock(){
+}
+
+void RWlock::wlock() {
+ bool &writer = write();
+ rwMutex.lock();
+ writer = true; // Remember this thread has write lock held.
+}
+
+void RWlock::rlock() {
+ bool &writer = write();
+ rwMutex.lock_shared();
+ writer = false; // Remember this thread has shared lock held.
+}
+
+void RWlock::unlock() {
+ bool &writer = write();
+ if (writer)
+ rwMutex.unlock();
+ else
+ rwMutex.unlock_shared();
+}
+
+void RWlock::trywlock() {
+ bool &writer = write();
+ // shared_mutex::try_lock() seems to not be available... emulate it with
+ // a timed lock().
+ boost::system_time now = boost::get_system_time();
+ if (rwMutex.timed_lock(now))
+ writer = true;
+}
+
+void RWlock::tryrlock() {
+ bool &writer = write();
+ if (rwMutex.try_lock_shared())
+ writer = false;
+}
+
+bool & RWlock::write (void) {
+ // Accessing thread-specific and stack-local info, so no locks needed.
+ bool *writePtr = haveWrite.get();
+ if (writePtr == 0) {
+ writePtr = new bool(false);
+ haveWrite.reset(writePtr);
+ }
+ return *writePtr;
+}
+
+}}
+#endif /*!_sys_windows_Mutex_h*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/windows/Shlib.cpp b/RC9/qpid/cpp/src/qpid/sys/windows/Shlib.cpp
new file mode 100644
index 0000000000..38027de93f
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/windows/Shlib.cpp
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Shlib.h"
+#include "qpid/Exception.h"
+#include "qpid/sys/windows/check.h"
+#include <windows.h>
+
+namespace qpid {
+namespace sys {
+
+void Shlib::load(const char* name) {
+ HMODULE h = LoadLibrary(name);
+ if (h == NULL) {
+ throw QPID_WINDOWS_ERROR(GetLastError());
+ }
+ handle = static_cast<void*>(h);
+}
+
+void Shlib::unload() {
+ if (handle) {
+ if (FreeLibrary(static_cast<HMODULE>(handle)) == 0) {
+ throw QPID_WINDOWS_ERROR(GetLastError());
+ }
+ handle = 0;
+ }
+}
+
+void* Shlib::getSymbol(const char* name) {
+ void* sym = GetProcAddress(static_cast<HMODULE>(handle), name);
+ if (sym == NULL)
+ throw QPID_WINDOWS_ERROR(GetLastError());
+ return sym;
+}
+
+}} // namespace qpid::sys
diff --git a/RC9/qpid/cpp/src/qpid/sys/windows/Socket.cpp b/RC9/qpid/cpp/src/qpid/sys/windows/Socket.cpp
new file mode 100755
index 0000000000..a9959bf43e
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/windows/Socket.cpp
@@ -0,0 +1,329 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Socket.h"
+#include "IoHandlePrivate.h"
+#include "check.h"
+#include "qpid/sys/Time.h"
+
+#include <cstdlib>
+#include <string.h>
+#include <iostream>
+#include <memory.h>
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+#include <boost/format.hpp>
+
+// Need to initialize WinSock. Ideally, this would be a singleton or embedded
+// in some one-time initialization function. I tried boost singleton and could
+// not get it to compile (and others located in google had the same problem).
+// So, this simple static with an interlocked increment will do for known
+// use cases at this time. Since this will only shut down winsock at process
+// termination, there may be some problems with client programs that also
+// expect to load and unload winsock, but we'll see...
+// If someone does get an easy-to-use singleton sometime, converting to it
+// may be preferable.
+
+namespace {
+
+static LONG volatile initialized = 0;
+
+class WinSockSetup {
+ // : public boost::details::pool::singleton_default<WinSockSetup> {
+
+public:
+ WinSockSetup() {
+ LONG timesEntered = InterlockedIncrement(&initialized);
+ if (timesEntered > 1)
+ return;
+ err = 0;
+ WORD wVersionRequested;
+ WSADATA wsaData;
+
+ /* Request WinSock 2.2 */
+ wVersionRequested = MAKEWORD(2, 2);
+ err = WSAStartup(wVersionRequested, &wsaData);
+ }
+
+ ~WinSockSetup() {
+ WSACleanup();
+ }
+
+public:
+ int error(void) const { return err; }
+
+protected:
+ DWORD err;
+};
+
+static WinSockSetup setup;
+
+} /* namespace */
+
+namespace qpid {
+namespace sys {
+
+namespace {
+
+std::string getName(SOCKET fd, bool local, bool includeService = false)
+{
+ sockaddr_in name; // big enough for any socket address
+ socklen_t namelen = sizeof(name);
+ if (local) {
+ QPID_WINSOCK_CHECK(::getsockname(fd, (sockaddr*)&name, &namelen));
+ } else {
+ QPID_WINSOCK_CHECK(::getpeername(fd, (sockaddr*)&name, &namelen));
+ }
+
+ char servName[NI_MAXSERV];
+ char dispName[NI_MAXHOST];
+ if (includeService) {
+ if (int rc = ::getnameinfo((sockaddr*)&name, namelen,
+ dispName, sizeof(dispName),
+ servName, sizeof(servName),
+ NI_NUMERICHOST | NI_NUMERICSERV) != 0)
+ throw qpid::Exception(QPID_MSG(gai_strerror(rc)));
+ return std::string(dispName) + ":" + std::string(servName);
+ } else {
+ if (int rc = ::getnameinfo((sockaddr*)&name, namelen,
+ dispName, sizeof(dispName),
+ 0, 0,
+ NI_NUMERICHOST) != 0)
+ throw qpid::Exception(QPID_MSG(gai_strerror(rc)));
+ return dispName;
+ }
+}
+
+std::string getService(SOCKET fd, bool local)
+{
+ sockaddr_in name; // big enough for any socket address
+ socklen_t namelen = sizeof(name);
+
+ if (local) {
+ QPID_WINSOCK_CHECK(::getsockname(fd, (sockaddr*)&name, &namelen));
+ } else {
+ QPID_WINSOCK_CHECK(::getpeername(fd, (sockaddr*)&name, &namelen));
+ }
+
+ char servName[NI_MAXSERV];
+ if (int rc = ::getnameinfo((sockaddr*)&name, namelen,
+ 0, 0,
+ servName, sizeof(servName),
+ NI_NUMERICHOST | NI_NUMERICSERV) != 0)
+ throw qpid::Exception(QPID_MSG(gai_strerror(rc)));
+ return servName;
+}
+} // namespace
+
+Socket::Socket() :
+ IOHandle(new IOHandlePrivate)
+{
+ createTcp();
+}
+
+Socket::Socket(IOHandlePrivate* h) :
+ IOHandle(h)
+{}
+
+void Socket::createTcp() const
+{
+ SOCKET& socket = impl->fd;
+ if (socket != INVALID_SOCKET) Socket::close();
+ SOCKET s = ::socket (PF_INET, SOCK_STREAM, 0);
+ if (s == INVALID_SOCKET) throw QPID_WINDOWS_ERROR(WSAGetLastError());
+ socket = s;
+}
+
+void Socket::setTimeout(const Duration& interval) const
+{
+ const SOCKET& socket = impl->fd;
+ int64_t nanosecs = interval;
+ nanosecs /= (1000 * 1000); // nsecs -> usec -> msec
+ int msec = 0;
+ if (nanosecs > std::numeric_limits<int>::max())
+ msec = std::numeric_limits<int>::max();
+ else
+ msec = static_cast<int>(nanosecs);
+ setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&msec, sizeof(msec));
+ setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&msec, sizeof(msec));
+}
+
+void Socket::setNonblocking() const {
+ u_long nonblock = 1;
+ QPID_WINSOCK_CHECK(ioctlsocket(impl->fd, FIONBIO, &nonblock));
+}
+
+void Socket::connect(const std::string& host, uint16_t port) const
+{
+ std::stringstream portstream;
+ portstream << port << std::ends;
+ std::string portstr = portstream.str();
+ std::stringstream namestream;
+ namestream << host << ":" << port;
+ connectname = namestream.str();
+
+ const SOCKET& socket = impl->fd;
+ // TODO: Be good to make this work for IPv6 as well as IPv4. Would require
+ // other changes, such as waiting to create the socket until after we
+ // have the address family. Maybe unbundle the translation of names here;
+ // use TcpAddress to resolve things and make this class take a TcpAddress
+ // and grab its address family to create the socket.
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET; // We always creating AF_INET-only sockets.
+ hints.ai_socktype = SOCK_STREAM; // We always do TCP
+ addrinfo *addrs;
+ int status = getaddrinfo(host.c_str(), portstr.c_str(), &hints, &addrs);
+ if (status != 0)
+ throw Exception(QPID_MSG("Cannot resolve " << host << ": " <<
+ gai_strerror(status)));
+ addrinfo *addr = addrs;
+ int error = 0;
+ WSASetLastError(0);
+ while (addr != 0) {
+ if ((::connect(socket, addr->ai_addr, addr->ai_addrlen) == 0) ||
+ (WSAGetLastError() == WSAEWOULDBLOCK))
+ break;
+ // Error... save this error code and see if there are other address
+ // to try before throwing the exception.
+ error = WSAGetLastError();
+ addr = addr->ai_next;
+ }
+ freeaddrinfo(addrs);
+ if (error)
+ throw qpid::Exception(QPID_MSG(strError(error) << ": " << connectname));
+}
+
+void
+Socket::close() const
+{
+ SOCKET& socket = impl->fd;
+ if (socket == INVALID_SOCKET) return;
+ QPID_WINSOCK_CHECK(closesocket(socket));
+ socket = INVALID_SOCKET;
+}
+
+
+int Socket::write(const void *buf, size_t count) const
+{
+ const SOCKET& socket = impl->fd;
+ int sent = ::send(socket, (const char *)buf, count, 0);
+ if (sent == SOCKET_ERROR)
+ return -1;
+ return sent;
+}
+
+int Socket::read(void *buf, size_t count) const
+{
+ const SOCKET& socket = impl->fd;
+ int received = ::recv(socket, (char *)buf, count, 0);
+ if (received == SOCKET_ERROR)
+ return -1;
+ return received;
+}
+
+int Socket::listen(uint16_t port, int backlog) const
+{
+ const SOCKET& socket = impl->fd;
+ BOOL yes=1;
+ QPID_WINSOCK_CHECK(setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)));
+ struct sockaddr_in name;
+ memset(&name, 0, sizeof(name));
+ name.sin_family = AF_INET;
+ name.sin_port = htons(port);
+ name.sin_addr.s_addr = 0;
+ if (::bind(socket, (struct sockaddr*)&name, sizeof(name)) == SOCKET_ERROR)
+ throw Exception(QPID_MSG("Can't bind to port " << port << ": " << strError(WSAGetLastError())));
+ if (::listen(socket, backlog) == SOCKET_ERROR)
+ throw Exception(QPID_MSG("Can't listen on port " << port << ": " << strError(WSAGetLastError())));
+
+ socklen_t namelen = sizeof(name);
+ QPID_WINSOCK_CHECK(::getsockname(socket, (struct sockaddr*)&name, &namelen));
+ return ntohs(name.sin_port);
+}
+
+Socket* Socket::accept(struct sockaddr *addr, socklen_t *addrlen) const
+{
+ SOCKET afd = ::accept(impl->fd, addr, addrlen);
+ if (afd != INVALID_SOCKET)
+ return new Socket(new IOHandlePrivate(afd));
+ else if (WSAGetLastError() == EAGAIN)
+ return 0;
+ else throw QPID_WINDOWS_ERROR(WSAGetLastError());
+}
+
+std::string Socket::getSockname() const
+{
+ return getName(impl->fd, true);
+}
+
+std::string Socket::getPeername() const
+{
+ return getName(impl->fd, false);
+}
+
+std::string Socket::getPeerAddress() const
+{
+ if (!connectname.empty())
+ return std::string (connectname);
+ return getName(impl->fd, false, true);
+}
+
+std::string Socket::getLocalAddress() const
+{
+ return getName(impl->fd, true, true);
+}
+
+uint16_t Socket::getLocalPort() const
+{
+ return atoi(getService(impl->fd, true).c_str());
+}
+
+uint16_t Socket::getRemotePort() const
+{
+ return atoi(getService(impl->fd, true).c_str());
+}
+
+int Socket::getError() const
+{
+ int result;
+ socklen_t rSize = sizeof (result);
+
+ QPID_WINSOCK_CHECK(::getsockopt(impl->fd, SOL_SOCKET, SO_ERROR, (char *)&result, &rSize));
+ return result;
+}
+
+void Socket::setTcpNoDelay(bool nodelay) const
+{
+ if (nodelay) {
+ int flag = 1;
+ int result = setsockopt(impl->fd,
+ IPPROTO_TCP,
+ TCP_NODELAY,
+ (char *)&flag,
+ sizeof(flag));
+ QPID_WINSOCK_CHECK(result);
+ }
+}
+
+}} // namespace qpid::sys
diff --git a/RC9/qpid/cpp/src/qpid/sys/windows/StrError.cpp b/RC9/qpid/cpp/src/qpid/sys/windows/StrError.cpp
new file mode 100755
index 0000000000..9c1bfcd79c
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/windows/StrError.cpp
@@ -0,0 +1,47 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/StrError.h"
+#include <string>
+#include <string.h>
+#include <windows.h>
+
+namespace qpid {
+namespace sys {
+
+std::string strError(int err) {
+ const size_t bufsize = 512;
+ char buf[bufsize];
+ if (0 == FormatMessage (FORMAT_MESSAGE_MAX_WIDTH_MASK
+ | FORMAT_MESSAGE_FROM_SYSTEM,
+ 0,
+ err,
+ 0, // Default language
+ buf,
+ bufsize,
+ 0))
+ {
+ strerror_s (buf, bufsize, err);
+ }
+ return std::string(buf);
+}
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/sys/windows/SystemInfo.cpp b/RC9/qpid/cpp/src/qpid/sys/windows/SystemInfo.cpp
new file mode 100755
index 0000000000..b887cac58b
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/windows/SystemInfo.cpp
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/* GetNativeSystemInfo call requires _WIN32_WINNT 0x0501 or higher */
+#ifndef _WIN32_WINNT
+# define _WIN32_WINNT 0x0501
+#endif
+
+#include "qpid/sys/IntegerTypes.h"
+#include "qpid/sys/SystemInfo.h"
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <windows.h>
+
+#ifndef HOST_NAME_MAX
+# define HOST_NAME_MAX 256
+#endif
+
+namespace qpid {
+namespace sys {
+
+long SystemInfo::concurrency() {
+ SYSTEM_INFO sys_info;
+ ::GetSystemInfo (&sys_info);
+ long activeProcessors = 0;
+ DWORD_PTR mask = sys_info.dwActiveProcessorMask;
+ while (mask != 0) {
+ if (mask & 1)
+ ++activeProcessors;
+ mask >>= 1;
+ }
+ return activeProcessors;
+}
+
+bool SystemInfo::getLocalHostname (TcpAddress &address) {
+ char name[HOST_NAME_MAX];
+ if (::gethostname(name, sizeof(name)) != 0) {
+ errno = WSAGetLastError();
+ return false;
+ }
+ address.host = name;
+ return true;
+}
+
+void SystemInfo::getLocalIpAddresses (uint16_t port,
+ std::vector<Address> &addrList) {
+ enum { MAX_URL_INTERFACES = 100 };
+ static const std::string LOCALHOST("127.0.0.1");
+
+ SOCKET s = socket (PF_INET, SOCK_STREAM, 0);
+ if (s != INVALID_SOCKET) {
+ INTERFACE_INFO interfaces[MAX_URL_INTERFACES];
+ DWORD filledBytes = 0;
+ WSAIoctl (s,
+ SIO_GET_INTERFACE_LIST,
+ 0,
+ 0,
+ interfaces,
+ sizeof (interfaces),
+ &filledBytes,
+ 0,
+ 0);
+ unsigned int interfaceCount = filledBytes / sizeof (INTERFACE_INFO);
+ for (unsigned int i = 0; i < interfaceCount; ++i) {
+ if (interfaces[i].iiFlags & IFF_UP) {
+ std::string addr(inet_ntoa(interfaces[i].iiAddress.AddressIn.sin_addr));
+ if (addr != LOCALHOST)
+ addrList.push_back(TcpAddress(addr, port));
+ }
+ }
+ closesocket (s);
+ }
+}
+
+void SystemInfo::getSystemId (std::string &osName,
+ std::string &nodeName,
+ std::string &release,
+ std::string &version,
+ std::string &machine)
+{
+ osName = "Microsoft Windows";
+
+ char node[MAX_COMPUTERNAME_LENGTH + 1];
+ DWORD nodelen = MAX_COMPUTERNAME_LENGTH + 1;
+ GetComputerName (node, &nodelen);
+ nodeName = node;
+
+ OSVERSIONINFOEX vinfo;
+ vinfo.dwOSVersionInfoSize = sizeof(vinfo);
+ GetVersionEx ((OSVERSIONINFO *)&vinfo);
+
+ SYSTEM_INFO sinfo;
+ GetNativeSystemInfo(&sinfo);
+
+ switch(vinfo.dwMajorVersion) {
+ case 5:
+ switch(vinfo.dwMinorVersion) {
+ case 0:
+ release ="2000";
+ break;
+ case 1:
+ release = "XP";
+ break;
+ case 2:
+ if (sinfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ||
+ sinfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64)
+ release = "XP-64";
+ else
+ release = "Server 2003";
+ break;
+ default:
+ release = "Windows";
+ }
+ break;
+ case 6:
+ if (vinfo.wProductType == VER_NT_SERVER)
+ release = "Server 2008";
+ else
+ release = "Vista";
+ break;
+ default:
+ release = "Microsoft Windows";
+ }
+ version = vinfo.szCSDVersion;
+
+ switch(sinfo.wProcessorArchitecture) {
+ case PROCESSOR_ARCHITECTURE_AMD64:
+ machine = "x86-64";
+ break;
+ case PROCESSOR_ARCHITECTURE_IA64:
+ machine = "IA64";
+ break;
+ case PROCESSOR_ARCHITECTURE_INTEL:
+ machine = "x86";
+ break;
+ default:
+ machine = "unknown";
+ break;
+ }
+}
+
+}} // namespace qpid::sys
diff --git a/RC9/qpid/cpp/src/qpid/sys/windows/Thread.cpp b/RC9/qpid/cpp/src/qpid/sys/windows/Thread.cpp
new file mode 100755
index 0000000000..6d5d78393e
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/windows/Thread.cpp
@@ -0,0 +1,88 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Thread.h"
+#include "qpid/sys/Runnable.h"
+#include "check.h"
+
+#include <process.h>
+#include <windows.h>
+
+namespace {
+unsigned __stdcall runRunnable(void* p)
+{
+ static_cast<qpid::sys::Runnable*>(p)->run();
+ _endthreadex(0);
+ return 0;
+}
+}
+
+namespace qpid {
+namespace sys {
+
+class ThreadPrivate {
+ friend class Thread;
+
+ HANDLE threadHandle;
+ unsigned threadId;
+
+ ThreadPrivate(Runnable* runnable) {
+ uintptr_t h = _beginthreadex(0,
+ 0,
+ runRunnable,
+ runnable,
+ 0,
+ &threadId);
+ QPID_WINDOWS_CHECK_CRT_NZ(h);
+ threadHandle = reinterpret_cast<HANDLE>(h);
+ }
+
+ ThreadPrivate()
+ : threadHandle(GetCurrentThread()), threadId(GetCurrentThreadId()) {}
+};
+
+Thread::Thread() {}
+
+Thread::Thread(Runnable* runnable) : impl(new ThreadPrivate(runnable)) {}
+
+Thread::Thread(Runnable& runnable) : impl(new ThreadPrivate(&runnable)) {}
+
+void Thread::join() {
+ if (impl) {
+ DWORD status = WaitForSingleObject (impl->threadHandle, INFINITE);
+ QPID_WINDOWS_CHECK_NOT(status, WAIT_FAILED);
+ CloseHandle (impl->threadHandle);
+ impl->threadHandle = 0;
+ }
+}
+
+unsigned long Thread::id() {
+ return impl ? impl->threadId : 0;
+}
+
+/* static */
+Thread Thread::current() {
+ Thread t;
+ t.impl.reset(new ThreadPrivate());
+ return t;
+}
+
+}} /* qpid::sys */
diff --git a/RC9/qpid/cpp/src/qpid/sys/windows/Time.cpp b/RC9/qpid/cpp/src/qpid/sys/windows/Time.cpp
new file mode 100644
index 0000000000..2390826831
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/windows/Time.cpp
@@ -0,0 +1,90 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Time.h"
+#include <ostream>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/thread/thread_time.hpp>
+#include <windows.h>
+
+using namespace boost::posix_time;
+
+namespace qpid {
+namespace sys {
+
+AbsTime::AbsTime(const AbsTime& t, const Duration& d) {
+ if (d == Duration::max()) {
+ timepoint = ptime(max_date_time);
+ }
+ else {
+ time_duration td = microseconds(d.nanosecs / 1000);
+ timepoint = t.timepoint + td;
+ }
+}
+
+AbsTime AbsTime::FarFuture() {
+ AbsTime ff;
+ ptime maxd(max_date_time);
+ ff.timepoint = maxd;
+ return ff;
+}
+
+AbsTime AbsTime::now() {
+ AbsTime time_now;
+ time_now.timepoint = boost::get_system_time();
+ return time_now;
+}
+
+Duration::Duration(const AbsTime& time0) : nanosecs(0) {
+ time_period p(ptime(min_date_time), time0.timepoint);
+ nanosecs = p.length().total_nanoseconds();
+}
+
+Duration::Duration(const AbsTime& start, const AbsTime& finish) {
+ time_duration d = finish.timepoint - start.timepoint;
+ nanosecs = d.total_nanoseconds();
+}
+
+std::ostream& operator<<(std::ostream& o, const Duration& d) {
+ return o << int64_t(d) << "ns";
+}
+
+std::ostream& operator<<(std::ostream& o, const AbsTime& t) {
+ std::string time_string = to_simple_string(t.timepoint);
+ return o << time_string;
+}
+
+void toPtime(ptime& pt, const AbsTime& t) {
+ pt = t.getPrivate();
+}
+
+void sleep(int secs) {
+ ::Sleep(secs * 1000);
+}
+
+void usleep(uint64_t usecs) {
+ DWORD msecs = usecs / 1000;
+ if (msecs == 0)
+ msecs = 1;
+ ::Sleep(msecs);
+}
+
+}}
diff --git a/RC9/qpid/cpp/src/qpid/sys/windows/Time.h b/RC9/qpid/cpp/src/qpid/sys/windows/Time.h
new file mode 100644
index 0000000000..49b3c4bab3
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/windows/Time.h
@@ -0,0 +1,36 @@
+#ifndef QPID_SYS_WINDOWS_TIME_H
+#define QPID_SYS_WINDOWS_TIME_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+
+namespace qpid {
+namespace sys {
+
+/**
+ * Class to represent an instant in time. Boost has this stuff already done
+ * so just reuse it. We can also grab this for quick use with the Condition
+ * wait operations.
+ */
+typedef boost::posix_time::ptime TimePrivate;
+
+}} // namespace qpid::sys
+
+#endif /*!QPID_SYS_WINDOWS_TIME_H*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/windows/check.h b/RC9/qpid/cpp/src/qpid/sys/windows/check.h
new file mode 100755
index 0000000000..aba38814b2
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/windows/check.h
@@ -0,0 +1,48 @@
+#ifndef _windows_check_h
+#define _windows_check_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/Exception.h"
+#include "qpid/sys/StrError.h"
+
+#define QPID_WINDOWS_ERROR(ERRVAL) qpid::Exception(QPID_MSG(qpid::sys::strError(ERRVAL)))
+#define QPID_WINDOWS_CRT_ERROR(ERRNO) qpid::Exception(QPID_MSG(qpid::sys::strError(ERRNO)))
+
+/** THROW QPID_WINDOWS_ERROR(::GetLastError()) if RESULT is NULL */
+#define QPID_WINDOWS_CHECK_NULL(RESULT) \
+ if ((RESULT) == NULL) throw QPID_WINDOWS_ERROR((::GetLastError()))
+
+#define QPID_WINDOWS_CHECK_NOT(RESULT,VAL) \
+ if ((RESULT) == (VAL)) throw QPID_WINDOWS_ERROR((::GetLastError()))
+
+#define QPID_WINDOWS_CHECK_ASYNC_START(STATUS) \
+ if (!(STATUS) && ::WSAGetLastError() != ERROR_IO_PENDING) \
+ throw QPID_WINDOWS_ERROR((::WSAGetLastError()))
+
+#define QPID_WINDOWS_CHECK_CRT_NZ(VAL) \
+ if ((VAL) == 0) throw QPID_WINDOWS_CRT_ERROR(errno)
+
+#define QPID_WINSOCK_CHECK(OP) \
+ if ((OP) == SOCKET_ERROR) throw QPID_WINDOWS_ERROR((::WSAGetLastError()))
+
+#endif /*!_windows_check_h*/
diff --git a/RC9/qpid/cpp/src/qpid/sys/windows/uuid.cpp b/RC9/qpid/cpp/src/qpid/sys/windows/uuid.cpp
new file mode 100644
index 0000000000..92f60e04b1
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/windows/uuid.cpp
@@ -0,0 +1,54 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "uuid.h"
+
+#include <string.h>
+
+void uuid_clear (uuid_t uu) {
+ UuidCreateNil (reinterpret_cast<UUID*>(uu));
+}
+
+void uuid_copy (uuid_t dst, const uuid_t src) {
+ memcpy (dst, src, qpid::sys::UuidSize);
+}
+
+void uuid_generate (uuid_t out) {
+ UuidCreate (reinterpret_cast<UUID*>(out));
+}
+
+int uuid_is_null (const uuid_t uu) {
+ RPC_STATUS unused;
+ return UuidIsNil ((UUID*)uu, &unused);
+}
+
+int uuid_parse (const char *in, uuid_t uu) {
+ return UuidFromString ((unsigned char*)in, (UUID*)uu) == RPC_S_OK ? 0 : -1;
+}
+
+void uuid_unparse (const uuid_t uu, char *out) {
+ unsigned char *formatted;
+ if (UuidToString((UUID*)uu, &formatted) == RPC_S_OK) {
+ strncpy_s (out, 36+1, (char*)formatted, _TRUNCATE);
+ RpcStringFree(&formatted);
+ }
+}
+
diff --git a/RC9/qpid/cpp/src/qpid/sys/windows/uuid.h b/RC9/qpid/cpp/src/qpid/sys/windows/uuid.h
new file mode 100644
index 0000000000..a44ef2e9a3
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/sys/windows/uuid.h
@@ -0,0 +1,41 @@
+#ifndef _sys_windows_uuid_h
+#define _sys_windows_uuid_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <Rpc.h>
+
+#ifdef uuid_t /* Done in rpcdce.h */
+# undef uuid_t
+#endif
+#include <qpid/sys/IntegerTypes.h>
+namespace qpid { namespace sys { const size_t UuidSize = 16; }}
+typedef uint8_t uuid_t[qpid::sys::UuidSize];
+
+void uuid_clear (uuid_t uu);
+void uuid_copy (uuid_t dst, const uuid_t src);
+void uuid_generate (uuid_t out);
+int uuid_is_null (const uuid_t uu); // Returns 1 if null, else 0
+int uuid_parse (const char *in, uuid_t uu); // Returns 0 on success, else -1
+void uuid_unparse (const uuid_t uu, char *out);
+
+#endif /*!_sys_windows_uuid_h*/
diff --git a/RC9/qpid/cpp/src/qpid/xml/XmlBinding.h b/RC9/qpid/cpp/src/qpid/xml/XmlBinding.h
new file mode 100644
index 0000000000..cc6b4dca5d
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/xml/XmlBinding.h
@@ -0,0 +1,37 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <qpid/framing/FieldTable>
+#include <string>
+
+#ifndef _XmlBinding_
+#define _XmlBinding_
+
+namespace qpid {
+namespace client {
+
+class XmlBinding : public framing::FieldTable {
+ public:
+ setQuery(string query) { setString("xquery", query); }
+};
+
+}
+}
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/xml/XmlExchange.cpp b/RC9/qpid/cpp/src/qpid/xml/XmlExchange.cpp
new file mode 100644
index 0000000000..5197b239d0
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/xml/XmlExchange.cpp
@@ -0,0 +1,263 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "config.h"
+
+#include "XmlExchange.h"
+
+#include "qpid/broker/DeliverableMessage.h"
+
+#include "qpid/log/Statement.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/FieldValue.h"
+#include "qpid/framing/reply_exceptions.h"
+
+#include "qpid/Plugin.h"
+
+#include <xercesc/framework/MemBufInputSource.hpp>
+#include <xqilla/context/ItemFactory.hpp>
+#include <xqilla/xqilla-simple.hpp>
+
+#include <iostream>
+#include <sstream>
+
+using namespace qpid::framing;
+using namespace qpid::sys;
+using qpid::management::Manageable;
+namespace _qmf = qmf::org::apache::qpid::broker;
+
+namespace qpid {
+namespace broker {
+
+
+XmlExchange::XmlExchange(const string& _name, Manageable* _parent) : Exchange(_name, _parent)
+{
+ if (mgmtExchange != 0)
+ mgmtExchange->set_type (typeName);
+}
+
+XmlExchange::XmlExchange(const std::string& _name, bool _durable,
+ const FieldTable& _args, Manageable* _parent) :
+ Exchange(_name, _durable, _args, _parent)
+{
+ if (mgmtExchange != 0)
+ mgmtExchange->set_type (typeName);
+}
+
+/*
+ * Use the name of the query as the binding key.
+ *
+ * The first time a given name is used in a binding, the query body
+ * must be provided.After that, no query body should be present.
+ *
+ * To modify an installed query, the user must first unbind the
+ * existing query, then replace it by binding again with the same
+ * name.
+ *
+ */
+
+ // #### TODO: The Binding should take the query text
+ // #### only. Consider encapsulating the entire block, including
+ // #### the if condition.
+
+
+bool XmlExchange::bind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* bindingArguments)
+{
+ string queryText = bindingArguments->getAsString("xquery");
+
+ try {
+ RWlock::ScopedWlock l(lock);
+
+ XmlBinding::vector& bindings(bindingsMap[routingKey]);
+ XmlBinding::vector::ConstPtr p = bindings.snapshot();
+ if (!p || std::find_if(p->begin(), p->end(), MatchQueue(queue)) == p->end()) {
+ Query query(xqilla.parse(X(queryText.c_str())));
+ XmlBinding::shared_ptr binding(new XmlBinding (routingKey, queue, this, query));
+ bindings.add(binding);
+ QPID_LOG(trace, "Bound successfully with query: " << queryText );
+
+ if (mgmtExchange != 0) {
+ mgmtExchange->inc_bindingCount();
+ ((_qmf::Queue*) queue->GetManagementObject())->inc_bindingCount();
+ }
+ } else {
+ return false;
+ }
+ }
+ catch (XQException& e) {
+ throw InternalErrorException(QPID_MSG("Could not parse xquery:"+ queryText));
+ }
+ catch (...) {
+ throw InternalErrorException(QPID_MSG("Unexpected error - Could not parse xquery:"+ queryText));
+ }
+ routeIVE();
+ return true;
+}
+
+bool XmlExchange::unbind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* /*args*/)
+{
+ RWlock::ScopedWlock l(lock);
+ if (bindingsMap[routingKey].remove_if(MatchQueue(queue))) {
+ if (mgmtExchange != 0) {
+ mgmtExchange->dec_bindingCount();
+ ((_qmf::Queue*) queue->GetManagementObject())->dec_bindingCount();
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool XmlExchange::matches(Query& query, Deliverable& msg, const qpid::framing::FieldTable* args)
+{
+ // ### TODO: Need istream for frameset
+ // Hack alert - the following code does not work for really large messages
+
+ string msgContent;
+
+ try {
+ msg.getMessage().getFrames().getContent(msgContent);
+
+ QPID_LOG(trace, "matches: query is [" << UTF8(query->getQueryText()) << "]");
+ QPID_LOG(trace, "matches: message content is [" << msgContent << "]");
+
+ boost::scoped_ptr<DynamicContext> context(query->createDynamicContext());
+ if (!context.get()) {
+ throw InternalErrorException(QPID_MSG("Query context looks munged ..."));
+ }
+
+ XERCES_CPP_NAMESPACE::MemBufInputSource xml((const XMLByte*) msgContent.c_str(),
+ msgContent.length(), "input" );
+ Sequence seq(context->parseDocument(xml));
+
+ if (args) {
+ FieldTable::ValueMap::const_iterator v = args->begin();
+ for(; v != args->end(); ++v) {
+ // ### TODO: Do types properly
+ if (v->second->convertsTo<std::string>()) {
+ QPID_LOG(trace, "XmlExchange, external variable: " << v->first << " = " << v->second->getData().getString().c_str());
+ Item::Ptr value = context->getItemFactory()->createString(X(v->second->getData().getString().c_str()), context.get());
+ context->setExternalVariable(X(v->first.c_str()), value);
+ }
+ }
+ }
+
+ if(!seq.isEmpty() && seq.first()->isNode()) {
+ context->setContextItem(seq.first());
+ context->setContextPosition(1);
+ context->setContextSize(1);
+ }
+ Result result = query->execute(context.get());
+ return result->getEffectiveBooleanValue(context.get(), 0);
+ }
+ catch (XQException& e) {
+ QPID_LOG(warning, "Could not parse XML content (or message headers):" << msgContent);
+ return 0;
+ }
+ catch (...) {
+ QPID_LOG(warning, "Unexpected error routing message: " << msgContent);
+ return 0;
+ }
+ return 0;
+}
+
+void XmlExchange::route(Deliverable& msg, const string& routingKey, const FieldTable* args)
+{
+ PreRoute pr(msg, this);
+ try {
+ XmlBinding::vector::ConstPtr p;
+ {
+ RWlock::ScopedRlock l(lock);
+ p = bindingsMap[routingKey].snapshot();
+ if (!p) return;
+ }
+ int count(0);
+
+ for (std::vector<XmlBinding::shared_ptr>::const_iterator i = p->begin(); i != p->end(); i++) {
+ if ((*i)->xquery && matches((*i)->xquery, msg, args)) { // Overly defensive? There should always be a query ...
+ msg.deliverTo((*i)->queue);
+ count++;
+ QPID_LOG(trace, "Delivered to queue" );
+
+ if ((*i)->mgmtBinding != 0)
+ (*i)->mgmtBinding->inc_msgMatched ();
+ }
+ }
+ if (!count) {
+ QPID_LOG(warning, "XMLExchange " << getName() << ": could not route message with query " << routingKey);
+ if (mgmtExchange != 0) {
+ mgmtExchange->inc_msgDrops ();
+ mgmtExchange->inc_byteDrops (msg.contentSize ());
+ }
+ } else {
+ if (mgmtExchange != 0) {
+ mgmtExchange->inc_msgRoutes (count);
+ mgmtExchange->inc_byteRoutes (count * msg.contentSize ());
+ }
+ }
+
+ if (mgmtExchange != 0) {
+ mgmtExchange->inc_msgReceives ();
+ mgmtExchange->inc_byteReceives (msg.contentSize ());
+ }
+ } catch (...) {
+ QPID_LOG(warning, "XMLExchange " << getName() << ": exception routing message with query " << routingKey);
+ }
+
+
+}
+
+
+bool XmlExchange::isBound(Queue::shared_ptr queue, const string* const routingKey, const FieldTable* const)
+{
+ RWlock::ScopedRlock l(lock);
+ if (routingKey) {
+ XmlBindingsMap::iterator i = bindingsMap.find(*routingKey);
+
+ if (i == bindingsMap.end())
+ return false;
+ if (!queue)
+ return true;
+ XmlBinding::vector::ConstPtr p = i->second.snapshot();
+ return p && std::find_if(p->begin(), p->end(), MatchQueue(queue)) != p->end();
+ } else if (!queue) {
+ //if no queue or routing key is specified, just report whether any bindings exist
+ return bindingsMap.size() > 0;
+ } else {
+ for (XmlBindingsMap::iterator i = bindingsMap.begin(); i != bindingsMap.end(); i++) {
+ XmlBinding::vector::ConstPtr p = i->second.snapshot();
+ if (p && std::find_if(p->begin(), p->end(), MatchQueue(queue)) != p->end()) return true;
+ }
+ return false;
+ }
+
+}
+
+
+XmlExchange::~XmlExchange()
+{
+ bindingsMap.clear();
+}
+
+const std::string XmlExchange::typeName("xml");
+
+}
+}
diff --git a/RC9/qpid/cpp/src/qpid/xml/XmlExchange.h b/RC9/qpid/cpp/src/qpid/xml/XmlExchange.h
new file mode 100644
index 0000000000..066a26489d
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/xml/XmlExchange.h
@@ -0,0 +1,88 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _XmlExchange_
+#define _XmlExchange_
+
+#include "qpid/broker/Exchange.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/sys/CopyOnWriteArray.h"
+#include "qpid/sys/Monitor.h"
+#include "qpid/broker/Queue.h"
+
+#include <xqilla/xqilla-simple.hpp>
+
+#include <boost/scoped_ptr.hpp>
+
+#include <map>
+#include <vector>
+
+namespace qpid {
+namespace broker {
+
+class XmlExchange : public virtual Exchange {
+
+ typedef boost::shared_ptr<XQQuery> Query;
+
+ struct XmlBinding : public Exchange::Binding {
+ typedef boost::shared_ptr<XmlBinding> shared_ptr;
+ typedef qpid::sys::CopyOnWriteArray<XmlBinding::shared_ptr> vector;
+
+ boost::shared_ptr<XQQuery> xquery;
+
+ XmlBinding(const std::string& key, const Queue::shared_ptr queue, Exchange* parent, Query query):
+ Binding(key, queue, parent), xquery(query) {}
+ };
+
+
+ typedef std::map<string, XmlBinding::vector > XmlBindingsMap;
+
+ XmlBindingsMap bindingsMap;
+ XQilla xqilla;
+ qpid::sys::RWlock lock;
+
+ bool matches(Query& query, Deliverable& msg, const qpid::framing::FieldTable* args);
+
+ public:
+ static const std::string typeName;
+
+ XmlExchange(const std::string& name, management::Manageable* parent = 0);
+ XmlExchange(const string& _name, bool _durable,
+ const qpid::framing::FieldTable& _args, management::Manageable* parent = 0);
+
+ virtual std::string getType() const { return typeName; }
+
+ virtual bool bind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args);
+
+ virtual bool unbind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args);
+
+ virtual void route(Deliverable& msg, const std::string& routingKey, const qpid::framing::FieldTable* args);
+
+ virtual bool isBound(Queue::shared_ptr queue, const string* const routingKey, const qpid::framing::FieldTable* const args);
+
+ virtual ~XmlExchange();
+};
+
+
+}
+}
+
+
+#endif
diff --git a/RC9/qpid/cpp/src/qpid/xml/XmlExchangePlugin.cpp b/RC9/qpid/cpp/src/qpid/xml/XmlExchangePlugin.cpp
new file mode 100644
index 0000000000..97e221589d
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpid/xml/XmlExchangePlugin.cpp
@@ -0,0 +1,67 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <sstream>
+#include "qpid/acl/Acl.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/Plugin.h"
+#include "qpid/shared_ptr.h"
+#include "qpid/log/Statement.h"
+
+#include <boost/utility/in_place_factory.hpp>
+
+#include "XmlExchange.h"
+
+namespace qpid {
+namespace broker { // ACL uses the acl namespace here - should I?
+
+using namespace std;
+
+Exchange::shared_ptr create(const std::string& name, bool durable,
+ const framing::FieldTable& args,
+ management::Manageable* parent)
+{
+ Exchange::shared_ptr e(new XmlExchange(name, durable, args, parent));
+ return e;
+}
+
+
+class XmlExchangePlugin : public Plugin
+{
+public:
+ void earlyInitialize(Plugin::Target& target);
+ void initialize(Plugin::Target& target);
+};
+
+
+void XmlExchangePlugin::initialize(Plugin::Target& target)
+{
+ Broker* broker = dynamic_cast<broker::Broker*>(&target);
+ if (broker) {
+ broker->getExchanges().registerType(XmlExchange::typeName, &create);
+ QPID_LOG(info, "Registered xml exchange");
+ }
+}
+
+void XmlExchangePlugin::earlyInitialize(Target&) {}
+
+
+static XmlExchangePlugin matchingPlugin;
+
+
+}} // namespace qpid::acl
diff --git a/RC9/qpid/cpp/src/qpidd.cpp b/RC9/qpid/cpp/src/qpidd.cpp
new file mode 100644
index 0000000000..330f12ae83
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpidd.cpp
@@ -0,0 +1,83 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpidd.h"
+#include "qpid/Plugin.h"
+#include "qpid/Version.h"
+#include "qpid/log/Logger.h"
+#include "qpid/log/Statement.h"
+#include "qpid/sys/Shlib.h"
+
+#include <iostream>
+#include <memory>
+using namespace std;
+
+auto_ptr<QpiddOptions> options;
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ {
+ BootstrapOptions bootOptions(argv[0]);
+ string defaultPath (bootOptions.module.loadDir);
+ // Parse only the common, load, and log options to see which
+ // modules need to be loaded. Once the modules are loaded,
+ // the command line will be re-parsed with all of the
+ // module-supplied options.
+ bootOptions.parse (argc, argv, bootOptions.common.config, true);
+ qpid::log::Logger::instance().configure(bootOptions.log);
+
+ for (vector<string>::iterator iter = bootOptions.module.load.begin();
+ iter != bootOptions.module.load.end();
+ iter++)
+ qpid::tryShlib (iter->data(), false);
+
+ if (!bootOptions.module.noLoad) {
+ bool isDefault = defaultPath == bootOptions.module.loadDir;
+ qpid::loadModuleDir (bootOptions.module.loadDir, isDefault);
+ }
+ }
+
+ // Parse options
+ options.reset(new QpiddOptions(argv[0]));
+ options->parse(argc, argv, options->common.config);
+
+ // Options that just print information.
+ if (options->common.help || options->common.version) {
+ if (options->common.version)
+ cout << "qpidd (" << qpid::product << ") version "
+ << qpid::version << endl;
+ else if (options->common.help)
+ options->usage();
+ return 0;
+ }
+
+ // Everything else is driven by the platform-specific broker
+ // logic.
+ QpiddBroker broker;
+ return broker.execute(options.get());
+ }
+ catch(const exception& e) {
+ QPID_LOG(critical, "Broker start-up failed: " << e.what());
+ }
+ return 1;
+}
diff --git a/RC9/qpid/cpp/src/qpidd.h b/RC9/qpid/cpp/src/qpidd.h
new file mode 100644
index 0000000000..c702270e80
--- /dev/null
+++ b/RC9/qpid/cpp/src/qpidd.h
@@ -0,0 +1,70 @@
+#ifndef QPID_H
+#define QPID_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/Modules.h"
+#include "qpid/Options.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/log/Options.h"
+
+#include <memory>
+
+// BootstrapOptions is a minimal subset of options used for a pre-parse
+// of the command line to discover which plugin modules need to be loaded.
+// The pre-parse is necessary because plugin modules may supply their own
+// set of options. CommonOptions is needed to properly support loading
+// from a configuration file.
+struct BootstrapOptions : public qpid::Options {
+ qpid::CommonOptions common;
+ qpid::ModuleOptions module;
+ qpid::log::Options log;
+
+ BootstrapOptions(const char *argv0);
+};
+
+// Each platform derives an options struct from QpiddOptionsPrivate, adding
+// platform-specific option types. QpiddOptions needs to allocation one of
+// these derived structs from its constructor.
+struct QpiddOptions;
+struct QpiddOptionsPrivate {
+ QpiddOptions *options;
+ QpiddOptionsPrivate(QpiddOptions *parent) : options(parent) {}
+ virtual ~QpiddOptionsPrivate() {}
+protected:
+ QpiddOptionsPrivate() {}
+};
+
+struct QpiddOptions : public qpid::Options {
+ qpid::CommonOptions common;
+ qpid::ModuleOptions module;
+ qpid::broker::Broker::Options broker;
+ qpid::log::Options log;
+ std::auto_ptr<QpiddOptionsPrivate> platform;
+
+ QpiddOptions(const char *argv0);
+ void usage() const;
+};
+
+class QpiddBroker {
+public:
+ int execute (QpiddOptions *options);
+};
+
+#endif /*!QPID_H*/
diff --git a/RC9/qpid/cpp/src/ssl.mk b/RC9/qpid/cpp/src/ssl.mk
new file mode 100644
index 0000000000..5b0ef3d8ae
--- /dev/null
+++ b/RC9/qpid/cpp/src/ssl.mk
@@ -0,0 +1,64 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+# Makefile fragment, conditionally included in Makefile.am
+#
+libsslcommon_la_SOURCES = \
+ qpid/sys/ssl/check.h \
+ qpid/sys/ssl/check.cpp \
+ qpid/sys/ssl/util.h \
+ qpid/sys/ssl/util.cpp \
+ qpid/sys/ssl/SslSocket.h \
+ qpid/sys/ssl/SslSocket.cpp \
+ qpid/sys/ssl/SslIo.h \
+ qpid/sys/ssl/SslIo.cpp
+
+libsslcommon_la_LIBADD= -lnss3 -lssl3 -lnspr4 libqpidcommon.la
+
+libsslcommon_la_CXXFLAGS=$(AM_CXXFLAGS) $(SSL_CFLAGS)
+
+lib_LTLIBRARIES += libsslcommon.la
+
+ssl_la_SOURCES = \
+ qpid/sys/SslPlugin.cpp \
+ qpid/sys/ssl/SslHandler.h \
+ qpid/sys/ssl/SslHandler.cpp
+
+ssl_la_LIBADD= libqpidbroker.la libsslcommon.la
+
+ssl_la_CXXFLAGS=$(AM_CXXFLAGS) $(SSL_CFLAGS)
+
+ssl_la_LDFLAGS = $(PLUGINLDFLAGS)
+
+dmodule_LTLIBRARIES += ssl.la
+
+
+sslconnector_la_SOURCES = \
+ qpid/client/SslConnector.cpp
+
+sslconnector_la_LIBADD = \
+ libqpidclient.la \
+ libsslcommon.la
+
+sslconnector_la_CXXFLAGS = $(AM_CXXFLAGS) -DCONF_FILE=\"$(confdir)/qpidc.conf\"
+
+sslconnector_la_LDFLAGS = $(PLUGINLDFLAGS)
+
+cmodule_LTLIBRARIES += \
+ sslconnector.la
diff --git a/RC9/qpid/cpp/src/tests/.valgrind.supp b/RC9/qpid/cpp/src/tests/.valgrind.supp
new file mode 100644
index 0000000000..7ac34fde5d
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/.valgrind.supp
@@ -0,0 +1,203 @@
+{
+ Benign error in libcpg.
+ Memcheck:Param
+ socketcall.sendmsg(msg.msg_iov[i])
+ obj:*/libpthread-2.5.so
+ obj:*/libcpg.so.2.0.0
+}
+
+{
+ Uninitialised value problem in _dl_relocate (F7, F8)
+ Memcheck:Cond
+ fun:_dl_relocate_object
+ fun:*dl_*
+}
+
+{
+ False "possibly leaked" in boost program_options - global std::string var.
+ Memcheck:Leak
+ fun:_Znwj
+ fun:_ZNSs4_Rep9_S_createEjjRKSaIcE
+ obj:/usr/lib/libstdc++.so.6.0.8
+ fun:_ZNSsC1EPKcRKSaIcE
+ obj:/usr/lib/libboost_program_options.so.1.33.1
+}
+
+{
+ boost 103200 -- we think Boost is responsible for these leaks.
+ Memcheck:Leak
+ fun:_Znwm
+ fun:_ZN5boost15program_options??options_description*
+}
+
+{
+ boost 103200 -- we think Boost is responsible for these leaks.
+ Memcheck:Leak
+ fun:_Znwm
+ fun:_ZN5boost9unit_test9test_case*
+}
+
+{
+ boost 103200 -- we think Boost is responsible for these leaks.
+ Memcheck:Leak
+ fun:calloc
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+ fun:_Z9testShlibv
+ fun:_ZN5boost9unit_test9ut_detail17unit_test_monitor8functionEv
+ obj:/usr/lib64/libboost_unit_test_framework.so.1.32.0
+ fun:_ZN5boost17execution_monitor7executeEbi
+ fun:_ZN5boost9unit_test9ut_detail17unit_test_monitor21execute_and_translateEPNS0_9test_caseEMS3_FvvEi
+ fun:_ZN5boost9unit_test9test_case3runEv
+ fun:_ZN5boost9unit_test10test_suite6do_runEv
+ fun:_ZN5boost9unit_test9test_case3runEv
+ fun:main
+}
+
+{
+ boost 103200 -- we think Boost is responsible for these leaks.
+ Memcheck:Leak
+ fun:calloc
+ fun:_dl_allocate_tls
+ fun:pthread_create@@GLIBC_2.2.5
+ fun:_ZN4qpid6broker5Timer5startEv
+ fun:_ZN4qpid6broker5TimerC1Ev
+ fun:_ZN4qpid6broker10DtxManagerC1Ev
+ fun:_ZN4qpid6broker6BrokerC1ERKNS1_7OptionsE
+ fun:_ZN4qpid6broker6Broker6createERKNS1_7OptionsE
+ fun:_ZN15SessionFixtureTI15ProxyConnectionEC2Ev
+ fun:_Z14testQueueQueryv
+ fun:_ZN5boost9unit_test9ut_detail17unit_test_monitor8functionEv
+ obj:/usr/lib64/libboost_unit_test_framework.so.1.32.0
+ fun:_ZN5boost17execution_monitor7executeEbi
+ fun:_ZN5boost9unit_test9ut_detail17unit_test_monitor21execute_and_translateEPNS0_9test_caseEMS3_FvvEi
+ fun:_ZN5boost9unit_test9test_case3runEv
+ fun:_ZN5boost9unit_test10test_suite6do_runEv
+ fun:_ZN5boost9unit_test9test_case3runEv
+ fun:main
+}
+
+{
+ INVESTIGATE
+ Memcheck:Leak
+ fun:calloc
+ fun:_dl_allocate_tls
+ fun:pthread_create@@GLIBC_2.2.5
+ fun:_ZN4qpid6client9Connector4initEv
+ fun:_ZN4qpid6client14ConnectionImpl4openERKSsiS3_S3_S3_
+}
+
+{
+ INVESTIGATE
+ Memcheck:Param
+ write(buf)
+ obj:/lib64/tls/libc-2.3.4.so
+ fun:_ZNK4qpid3sys6Socket5writeEPKvm
+ fun:_ZN4qpid3sys8AsynchIO9writeableERNS0_14DispatchHandleE
+}
+
+{
+ "Conditional jump or move depends on uninitialised value(s)" from Xerces parser
+ Memcheck:Cond
+ fun:_ZN11xercesc_2_717XMLUTF8Transcoder13transcodeFromEPKhjPtjRjPh
+ fun:_ZN11xercesc_2_79XMLReader14xcodeMoreCharsEPtPhj
+ fun:_ZN11xercesc_2_79XMLReader17refreshCharBufferEv
+}
+
+{
+ boost 103200 -- mgoulish -- fix this, sometime
+ Memcheck:Leak
+ fun:*
+ fun:*
+ obj:*
+ fun:*
+ fun:_ZN4qpid34options_description_less_easy_initclEPKcPKN5boost15program_options14value_semanticES2_
+}
+
+{
+ boost 103200 -- mgoulish -- fix this, sometime
+ Memcheck:Leak
+ fun:*
+ fun:*
+ fun:*
+ fun:_ZN4qpid34options_description_less_easy_initclEPKcPKN5boost15program_options14value_semanticES2_
+}
+
+{
+ INVESTIGATE
+ Memcheck:Param
+ socketcall.sendto(msg)
+ fun:send
+ fun:get_mapping
+ fun:__nscd_get_map_ref
+ fun:nscd_gethst_r
+ fun:__nscd_gethostbyname_r
+ fun:gethostbyname_r@@GLIBC_2.2.5
+ fun:gethostbyname
+ fun:_ZNK4qpid3sys6Socket7connectERKSsi
+}
+
+{
+ INVESTIGATE
+ Memcheck:Leak
+ fun:calloc
+ fun:_dl_allocate_tls
+ fun:pthread_create@@GLIBC_2.2.5
+ fun:_ZN4qpid6broker5Timer5startEv
+ fun:_ZN4qpid6broker5TimerC1Ev
+ fun:_ZN4qpid6broker10DtxManagerC1Ev
+ fun:_ZN4qpid6broker6BrokerC1ERKNS1_7OptionsE
+ fun:_ZN4qpid6broker6Broker6createERKNS1_7OptionsE
+ fun:_ZN20ClientSessionFixtureC1Ev
+ fun:_Z14testQueueQueryv
+ fun:_ZN5boost9unit_test9ut_detail17unit_test_monitor8functionEv
+ obj:/usr/lib64/libboost_unit_test_framework.so.1.32.0
+ fun:_ZN5boost17execution_monitor7executeEbi
+ fun:_ZN5boost9unit_test9ut_detail17unit_test_monitor21execute_and_translateEPNS0_9test_caseEMS3_FvvEi
+ fun:_ZN5boost9unit_test9test_case3runEv
+ fun:_ZN5boost9unit_test10test_suite6do_runEv
+ fun:_ZN5boost9unit_test9test_case3runEv
+ fun:main
+}
+
+{
+ INVESTIGATE
+ Memcheck:Leak
+ fun:calloc
+ fun:_dl_allocate_tls
+ fun:pthread_create@@GLIBC_2.2.5
+ fun:_ZN4qpid6client9Connector4initEv
+}
+
+{
+ MICK -- FIX
+ Memcheck:Leak
+ fun:_Znam
+ fun:_ZN4qpid7Options5parseEiPPcRKSsb
+}
+
+{
+ MICK -- FIX
+ Memcheck:Leak
+ fun:malloc
+ fun:strdup
+ fun:_ZN4qpid7Options5parseEiPPcRKSsb
+}
+
+{
+ CPG error - seems benign.
+ Memcheck:Param
+ socketcall.sendmsg(msg.msg_iov[i])
+ obj:*
+ obj:*/libcpg.so.2.0.0
+}
+
+{
+ Known leak in boost.thread 1.33.1. Wildcards for 64/32 bit diffs.
+ Memcheck:Leak
+ fun:*
+ obj:/usr/*/libboost_thread.so.1.33.1
+ fun:_ZN5boost6detail3tss3setEPv
+}
+
diff --git a/RC9/qpid/cpp/src/tests/AccumulatedAckTest.cpp b/RC9/qpid/cpp/src/tests/AccumulatedAckTest.cpp
new file mode 100644
index 0000000000..028ce71907
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/AccumulatedAckTest.cpp
@@ -0,0 +1,232 @@
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/framing/AccumulatedAck.h"
+#include "unit_test.h"
+#include <iostream>
+#include <list>
+
+using std::list;
+using namespace qpid::framing;
+
+
+bool covers(const AccumulatedAck& ack, int i)
+{
+ return ack.covers(SequenceNumber(i));
+}
+
+void update(AccumulatedAck& ack, int start, int end)
+{
+ ack.update(SequenceNumber(start), SequenceNumber(end));
+}
+
+QPID_AUTO_TEST_SUITE(AccumulatedAckTestSuite)
+
+QPID_AUTO_TEST_CASE(testGeneral)
+{
+ AccumulatedAck ack(0);
+ ack.clear();
+ update(ack, 3,3);
+ update(ack, 7,7);
+ update(ack, 9,9);
+ update(ack, 1,2);
+ update(ack, 4,5);
+ update(ack, 6,6);
+
+ for(int i = 1; i <= 7; i++) BOOST_CHECK(covers(ack, i));
+ BOOST_CHECK(covers(ack, 9));
+
+ BOOST_CHECK(!covers(ack, 8));
+ BOOST_CHECK(!covers(ack, 10));
+
+ ack.consolidate();
+
+ for(int i = 1; i <= 7; i++) BOOST_CHECK(covers(ack, i));
+ BOOST_CHECK(covers(ack, 9));
+
+ BOOST_CHECK(!covers(ack, 8));
+ BOOST_CHECK(!covers(ack, 10));
+}
+
+QPID_AUTO_TEST_CASE(testCovers)
+{
+ AccumulatedAck ack(5);
+ update(ack, 7, 7);
+ update(ack, 9, 9);
+
+ BOOST_CHECK(covers(ack, 1));
+ BOOST_CHECK(covers(ack, 2));
+ BOOST_CHECK(covers(ack, 3));
+ BOOST_CHECK(covers(ack, 4));
+ BOOST_CHECK(covers(ack, 5));
+ BOOST_CHECK(covers(ack, 7));
+ BOOST_CHECK(covers(ack, 9));
+
+ BOOST_CHECK(!covers(ack, 6));
+ BOOST_CHECK(!covers(ack, 8));
+ BOOST_CHECK(!covers(ack, 10));
+}
+
+QPID_AUTO_TEST_CASE(testUpdateFromCompletionData)
+{
+ AccumulatedAck ack(0);
+ SequenceNumber mark(2);
+ SequenceNumberSet ranges;
+ ranges.addRange(SequenceNumber(5), SequenceNumber(8));
+ ranges.addRange(SequenceNumber(10), SequenceNumber(15));
+ ranges.addRange(SequenceNumber(9), SequenceNumber(9));
+ ranges.addRange(SequenceNumber(3), SequenceNumber(4));
+
+ ack.update(mark, ranges);
+
+ for(int i = 0; i <= 15; i++) {
+ BOOST_CHECK(covers(ack, i));
+ }
+ BOOST_CHECK(!covers(ack, 16));
+ BOOST_CHECK_EQUAL((uint32_t) 15, ack.mark.getValue());
+}
+
+QPID_AUTO_TEST_CASE(testCase1)
+{
+ AccumulatedAck ack(3);
+ update(ack, 1,2);
+ for(int i = 1; i <= 3; i++) BOOST_CHECK(covers(ack, i));
+ BOOST_CHECK(!covers(ack, 4));
+}
+
+QPID_AUTO_TEST_CASE(testCase2)
+{
+ AccumulatedAck ack(3);
+ update(ack, 3,6);
+ for(int i = 1; i <= 6; i++) BOOST_CHECK(covers(ack, i));
+ BOOST_CHECK(!covers(ack, 7));
+}
+
+QPID_AUTO_TEST_CASE(testCase3)
+{
+ AccumulatedAck ack(3);
+ update(ack, 4,6);
+ for(int i = 1; i <= 6; i++) {
+ BOOST_CHECK(covers(ack, i));
+ }
+ BOOST_CHECK(!covers(ack, 7));
+}
+
+QPID_AUTO_TEST_CASE(testCase4)
+{
+ AccumulatedAck ack(3);
+ update(ack, 5,6);
+ for(int i = 1; i <= 6; i++) {
+ if (i == 4) BOOST_CHECK(!covers(ack, i));
+ else BOOST_CHECK(covers(ack, i));
+ }
+ BOOST_CHECK(!covers(ack, 7));
+}
+
+QPID_AUTO_TEST_CASE(testConsolidation1)
+{
+ AccumulatedAck ack(3);
+ update(ack, 7,7);
+ BOOST_CHECK_EQUAL((uint32_t) 3, ack.mark.getValue());
+ BOOST_CHECK_EQUAL((size_t) 1, ack.ranges.size());
+
+ update(ack, 8,9);
+ BOOST_CHECK_EQUAL((uint32_t) 3, ack.mark.getValue());
+ BOOST_CHECK_EQUAL((size_t) 1, ack.ranges.size());
+
+ update(ack, 1,2);
+ BOOST_CHECK_EQUAL((uint32_t) 3, ack.mark.getValue());
+ BOOST_CHECK_EQUAL((size_t) 1, ack.ranges.size());
+
+ update(ack, 4,5);
+ BOOST_CHECK_EQUAL((uint32_t) 5, ack.mark.getValue());
+ BOOST_CHECK_EQUAL((size_t) 1, ack.ranges.size());
+
+ update(ack, 6,6);
+ BOOST_CHECK_EQUAL((uint32_t) 9, ack.mark.getValue());
+ BOOST_CHECK_EQUAL((size_t) 0, ack.ranges.size());
+
+ for(int i = 1; i <= 9; i++) BOOST_CHECK(covers(ack, i));
+ BOOST_CHECK(!covers(ack, 10));
+}
+
+QPID_AUTO_TEST_CASE(testConsolidation2)
+{
+ AccumulatedAck ack(0);
+ update(ack, 10,12);
+ BOOST_CHECK_EQUAL((uint32_t) 0, ack.mark.getValue());
+ BOOST_CHECK_EQUAL((size_t) 1, ack.ranges.size());
+
+ update(ack, 7,9);
+ BOOST_CHECK_EQUAL((uint32_t) 0, ack.mark.getValue());
+ BOOST_CHECK_EQUAL((size_t) 1, ack.ranges.size());
+ BOOST_CHECK_EQUAL((uint32_t) 7, ack.ranges.front().start.getValue());
+ BOOST_CHECK_EQUAL((uint32_t) 12, ack.ranges.front().end.getValue());
+
+ update(ack, 5,7);
+ BOOST_CHECK_EQUAL((uint32_t) 0, ack.mark.getValue());
+ BOOST_CHECK_EQUAL((size_t) 1, ack.ranges.size());
+ BOOST_CHECK_EQUAL((uint32_t) 5, ack.ranges.front().start.getValue());
+ BOOST_CHECK_EQUAL((uint32_t) 12, ack.ranges.front().end.getValue());
+
+ update(ack, 3,4);
+ BOOST_CHECK_EQUAL((uint32_t) 0, ack.mark.getValue());
+ BOOST_CHECK_EQUAL((size_t) 1, ack.ranges.size());
+ BOOST_CHECK_EQUAL((uint32_t) 3, ack.ranges.front().start.getValue());
+ BOOST_CHECK_EQUAL((uint32_t) 12, ack.ranges.front().end.getValue());
+
+ update(ack, 1,2);
+ BOOST_CHECK_EQUAL((uint32_t) 12, ack.mark.getValue());
+ BOOST_CHECK_EQUAL((size_t) 0, ack.ranges.size());
+
+ for(int i = 1; i <= 12; i++) BOOST_CHECK(covers(ack, i));
+ BOOST_CHECK(!covers(ack, 13));
+}
+
+QPID_AUTO_TEST_CASE(testConsolidation3)
+{
+ AccumulatedAck ack(0);
+ update(ack, 10,12);
+ update(ack, 6,7);
+ update(ack, 3,4);
+ update(ack, 1,15);
+ BOOST_CHECK_EQUAL((uint32_t) 15, ack.mark.getValue());
+ BOOST_CHECK_EQUAL((size_t) 0, ack.ranges.size());
+}
+
+QPID_AUTO_TEST_CASE(testConsolidation4)
+{
+ AccumulatedAck ack(0);
+ ack.update(SequenceNumber(0), SequenceNumber(2));
+ ack.update(SequenceNumber(5), SequenceNumber(8));
+ ack.update(SequenceNumber(10), SequenceNumber(15));
+ ack.update(SequenceNumber(9), SequenceNumber(9));
+ ack.update(SequenceNumber(3), SequenceNumber(4));
+
+ for(int i = 0; i <= 15; i++) {
+ BOOST_CHECK(covers(ack, i));
+ }
+ BOOST_CHECK(!covers(ack, 16));
+ BOOST_CHECK_EQUAL((uint32_t) 15, ack.mark.getValue());
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
diff --git a/RC9/qpid/cpp/src/tests/Array.cpp b/RC9/qpid/cpp/src/tests/Array.cpp
new file mode 100644
index 0000000000..c779cbe901
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/Array.cpp
@@ -0,0 +1,79 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <iostream>
+#include <sstream>
+#include "qpid/framing/Array.h"
+#include "qpid/framing/FieldValue.h"
+
+#include "unit_test.h"
+
+QPID_AUTO_TEST_SUITE(ArrayTestSuite)
+
+using namespace qpid::framing;
+
+void populate(std::vector<std::string>& data, int count = 10)
+{
+ for (int i = 0; i < count; i++) {
+ std::stringstream out;
+ out << "item-" << i;
+ data.push_back(out.str());
+ }
+}
+
+QPID_AUTO_TEST_CASE(testEncodeDecode)
+{
+ std::vector<std::string> data;
+ populate(data);
+
+ Array a(data);
+
+ char buff[200];
+ Buffer wbuffer(buff, 200);
+ a.encode(wbuffer);
+
+ Array b;
+ Buffer rbuffer(buff, 200);
+ b.decode(rbuffer);
+ BOOST_CHECK_EQUAL(a, b);
+
+ std::vector<std::string> data2;
+ b.collect(data2);
+ //BOOST_CHECK_EQUAL(data, data2);
+ BOOST_CHECK(data == data2);
+}
+
+QPID_AUTO_TEST_CASE(testArrayAssignment)
+{
+ std::vector<std::string> data;
+ populate(data);
+ Array b;
+ {
+ Array a(data);
+ b = a;
+ BOOST_CHECK_EQUAL(a, b);
+ }
+ std::vector<std::string> data2;
+ b.collect(data2);
+ //BOOST_CHECK_EQUAL(data, data2);
+ BOOST_CHECK(data == data2);
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/AsyncCompletion.cpp b/RC9/qpid/cpp/src/tests/AsyncCompletion.cpp
new file mode 100644
index 0000000000..e33b2dc35d
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/AsyncCompletion.cpp
@@ -0,0 +1,100 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+#include "unit_test.h"
+#include "test_tools.h"
+#include "BrokerFixture.h"
+#include "qpid/broker/NullMessageStore.h"
+#include "qpid/sys/BlockingQueue.h"
+#include "qpid/client/AsyncSession.h"
+#include "qpid/sys/Time.h"
+
+using namespace std;
+using namespace qpid;
+using namespace client;
+using namespace framing;
+
+namespace qpid { namespace broker {
+class TransactionContext;
+class PersistableQueue;
+}}
+
+using broker::PersistableMessage;
+using broker::NullMessageStore;
+using broker::TransactionContext;
+using broker::PersistableQueue;
+using sys::TIME_SEC;
+using boost::intrusive_ptr;
+
+/** @file Unit tests for async completion.
+ * Using a dummy store, verify that the broker indicates async completion of
+ * message enqueues at the correct time.
+ */
+
+class AsyncCompletionMessageStore : public NullMessageStore {
+ public:
+ sys::BlockingQueue<boost::intrusive_ptr<PersistableMessage> > enqueued;
+
+ AsyncCompletionMessageStore() : NullMessageStore() {}
+ ~AsyncCompletionMessageStore(){}
+
+ void enqueue(TransactionContext*,
+ const boost::intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue& )
+ {
+ enqueued.push(msg);
+ }
+};
+
+QPID_AUTO_TEST_SUITE(AsyncCompletionTestSuite)
+
+QPID_AUTO_TEST_CASE(testWaitTillComplete) {
+ AsyncCompletionMessageStore* store = new AsyncCompletionMessageStore;
+ SessionFixture fix;
+ fix.broker->setStore(store); // Broker will delete store.
+ AsyncSession s = fix.session;
+
+ static const int count = 3;
+
+ s.queueDeclare("q", arg::durable=true);
+ Completion transfers[count];
+ for (int i = 0; i < count; ++i) {
+ Message msg(boost::lexical_cast<string>(i), "q");
+ msg.getDeliveryProperties().setDeliveryMode(PERSISTENT);
+ transfers[i] = s.messageTransfer(arg::content=msg);
+ }
+
+ // Get hold of the broker-side messages.
+ typedef vector<intrusive_ptr<PersistableMessage> > BrokerMessages;
+ BrokerMessages enqueued;
+ for (int j = 0; j < count; ++j)
+ enqueued.push_back(store->enqueued.pop(TIME_SEC));
+
+ // Send a sync, make sure it does not complete till all messages are complete.
+ // In reverse order for fun.
+ Completion sync = s.executionSync(arg::sync=true);
+ for (int k = count-1; k >= 0; --k) {
+ BOOST_CHECK(!transfers[k].isComplete()); // Should not be complete yet.
+ BOOST_CHECK(!sync.isComplete()); // Should not be complete yet.
+ enqueued[k]->enqueueComplete();
+ }
+ sync.wait(); // Should complete now, all messages are completed.
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/AtomicValue.cpp b/RC9/qpid/cpp/src/tests/AtomicValue.cpp
new file mode 100644
index 0000000000..05083ad177
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/AtomicValue.cpp
@@ -0,0 +1,49 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+#include "unit_test.h"
+#include "test_tools.h"
+#include "qpid/sys/AtomicValue.h"
+
+QPID_AUTO_TEST_SUITE(AtomicValueTestSuite)
+
+QPID_AUTO_TEST_CASE(test) {
+ qpid::sys::AtomicValue<int> x(0);
+ BOOST_CHECK_EQUAL(++x, 1);
+ BOOST_CHECK_EQUAL(--x,0);
+ BOOST_CHECK_EQUAL(x+=5,5);
+ BOOST_CHECK_EQUAL(x-=10,-5);
+ BOOST_CHECK_EQUAL(x.fetchAndAdd(7), -5);
+ BOOST_CHECK_EQUAL(x.get(),2);
+ BOOST_CHECK_EQUAL(x.fetchAndSub(3), 2);
+ BOOST_CHECK_EQUAL(x.get(),-1);
+
+ BOOST_CHECK_EQUAL(x.valueCompareAndSwap(-1,10), -1);
+ BOOST_CHECK_EQUAL(x.get(), 10);
+ BOOST_CHECK_EQUAL(x.valueCompareAndSwap(5, 6), 10);
+ BOOST_CHECK_EQUAL(x.get(), 10);
+
+ BOOST_CHECK(!x.boolCompareAndSwap(5, 6));
+ BOOST_CHECK_EQUAL(x.get(), 10);
+ BOOST_CHECK(x.boolCompareAndSwap(10, 6));
+ BOOST_CHECK_EQUAL(x.get(), 6);
+}
+
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/BasicP2PTest.cpp b/RC9/qpid/cpp/src/tests/BasicP2PTest.cpp
new file mode 100644
index 0000000000..f4a4cce7f2
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/BasicP2PTest.cpp
@@ -0,0 +1,66 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "BasicP2PTest.h"
+
+using namespace qpid;
+using namespace qpid::client;
+
+class BasicP2PTest::Receiver : public Worker, public MessageListener
+{
+ const std::string queue;
+ std::string tag;
+public:
+ Receiver(ConnectionOptions& options, const std::string& _queue, const int _messages)
+ : Worker(options, _messages), queue(_queue){}
+ void init()
+ {
+ Queue q(queue, true);
+ channel.declareQueue(q);
+ framing::FieldTable args;
+ channel.bind(Exchange::STANDARD_DIRECT_EXCHANGE, q, queue, args);
+ channel.consume(q, tag, this);
+ channel.start();
+ }
+
+ void start()
+ {
+ }
+
+ void received(Message&)
+ {
+ count++;
+ }
+};
+
+void BasicP2PTest::assign(const std::string& role, framing::FieldTable& params, ConnectionOptions& options)
+{
+ std::string queue = params.getString("P2P_QUEUE_AND_KEY_NAME");
+ int messages = params.getInt("P2P_NUM_MESSAGES");
+ if (role == "SENDER") {
+ worker = std::auto_ptr<Worker>(new Sender(options, Exchange::STANDARD_DIRECT_EXCHANGE, queue, messages));
+ } else if(role == "RECEIVER"){
+ worker = std::auto_ptr<Worker>(new Receiver(options, queue, messages));
+ } else {
+ throw Exception("unrecognised role");
+ }
+ worker->init();
+}
diff --git a/RC9/qpid/cpp/src/tests/BasicP2PTest.h b/RC9/qpid/cpp/src/tests/BasicP2PTest.h
new file mode 100644
index 0000000000..b2611f0301
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/BasicP2PTest.h
@@ -0,0 +1,46 @@
+#ifndef _BasicP2PTest_
+#define _BasicP2PTest_
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <memory>
+#include <sstream>
+
+#include "qpid/Exception.h"
+#include "qpid/client/Channel.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/MessageListener.h"
+#include "SimpleTestCaseBase.h"
+
+
+namespace qpid {
+
+class BasicP2PTest : public SimpleTestCaseBase
+{
+ class Receiver;
+public:
+ void assign(const std::string& role, framing::FieldTable& params, ConnectionOptions& options);
+};
+
+}
+
+#endif
diff --git a/RC9/qpid/cpp/src/tests/BasicPubSubTest.cpp b/RC9/qpid/cpp/src/tests/BasicPubSubTest.cpp
new file mode 100644
index 0000000000..1e9ff364f1
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/BasicPubSubTest.cpp
@@ -0,0 +1,121 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "BasicPubSubTest.h"
+
+using namespace qpid;
+
+class BasicPubSubTest::Receiver : public Worker, public MessageListener
+{
+ const Exchange& exchange;
+ const std::string queue;
+ const std::string key;
+ std::string tag;
+public:
+ Receiver(ConnectionOptions& options, const Exchange& _exchange, const std::string& _queue, const std::string& _key, const int _messages)
+ : Worker(options, _messages), exchange(_exchange), queue(_queue), key(_key){}
+
+ void init()
+ {
+ Queue q(queue, true);
+ channel.declareQueue(q);
+ framing::FieldTable args;
+ channel.bind(exchange, q, key, args);
+ channel.consume(q, tag, this);
+ channel.start();
+ }
+
+ void start(){
+ }
+
+ void received(Message&)
+ {
+ count++;
+ }
+};
+
+class BasicPubSubTest::MultiReceiver : public Worker, public MessageListener
+{
+ typedef boost::ptr_vector<Receiver> ReceiverList;
+ ReceiverList receivers;
+
+public:
+ MultiReceiver(ConnectionOptions& options, const Exchange& exchange, const std::string& key, const int _messages, int receiverCount)
+ : Worker(options, _messages)
+ {
+ for (int i = 0; i != receiverCount; i++) {
+ std::string queue = (boost::format("%1%_%2%") % options.clientid % i).str();
+ receivers.push_back(new Receiver(options, exchange, queue, key, _messages));
+ }
+ }
+
+ void init()
+ {
+ for (ReceiverList::size_type i = 0; i != receivers.size(); i++) {
+ receivers[i].init();
+ }
+ }
+
+ void start()
+ {
+ for (ReceiverList::size_type i = 0; i != receivers.size(); i++) {
+ receivers[i].start();
+ }
+ }
+
+ void received(Message& msg)
+ {
+ for (ReceiverList::size_type i = 0; i != receivers.size(); i++) {
+ receivers[i].received(msg);
+ }
+ }
+
+ virtual int getCount()
+ {
+ count = 0;
+ for (ReceiverList::size_type i = 0; i != receivers.size(); i++) {
+ count += receivers[i].getCount();
+ }
+ return count;
+ }
+ virtual void stop()
+ {
+ for (ReceiverList::size_type i = 0; i != receivers.size(); i++) {
+ receivers[i].stop();
+ }
+ }
+};
+
+void BasicPubSubTest::assign(const std::string& role, framing::FieldTable& params, ConnectionOptions& options)
+{
+ std::string key = params.getString("PUBSUB_KEY");
+ int messages = params.getInt("PUBSUB_NUM_MESSAGES");
+ int receivers = params.getInt("PUBSUB_NUM_RECEIVERS");
+ if (role == "SENDER") {
+ worker = std::auto_ptr<Worker>(new Sender(options, Exchange::STANDARD_TOPIC_EXCHANGE, key, messages));
+ } else if(role == "RECEIVER"){
+ worker = std::auto_ptr<Worker>(new MultiReceiver(options, Exchange::STANDARD_TOPIC_EXCHANGE, key, messages, receivers));
+ } else {
+ throw Exception("unrecognised role");
+ }
+ worker->init();
+}
+
diff --git a/RC9/qpid/cpp/src/tests/BasicPubSubTest.h b/RC9/qpid/cpp/src/tests/BasicPubSubTest.h
new file mode 100644
index 0000000000..242d2847d7
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/BasicPubSubTest.h
@@ -0,0 +1,51 @@
+#ifndef _BasicPubSubTest_
+#define _BasicPubSubTest_
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <memory>
+#include <sstream>
+
+#include "qpid/Exception.h"
+#include "qpid/client/Channel.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/MessageListener.h"
+#include "SimpleTestCaseBase.h"
+#include <boost/ptr_container/ptr_vector.hpp>
+#include <boost/format.hpp>
+
+
+namespace qpid {
+
+using namespace qpid::client;
+
+class BasicPubSubTest : public SimpleTestCaseBase
+{
+ class Receiver;
+ class MultiReceiver;
+public:
+ void assign(const std::string& role, framing::FieldTable& params, ConnectionOptions& options);
+};
+
+}
+
+#endif
diff --git a/RC9/qpid/cpp/src/tests/Blob.cpp b/RC9/qpid/cpp/src/tests/Blob.cpp
new file mode 100644
index 0000000000..c40e43b96e
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/Blob.cpp
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include "qpid/framing/Blob.h"
+
+#include "unit_test.h"
+
+QPID_AUTO_TEST_SUITE(BlobTestSuite)
+
+using namespace std;
+using namespace qpid::framing;
+
+struct Base {
+ int id;
+ int magic;
+
+ Base(int n) : id(n), magic(42) {}
+ Base(const Base& c) : id(c.id), magic(42) {}
+ ~Base() { BOOST_CHECK_EQUAL(42, magic); } // Detect random data.
+};
+
+template <class T> struct Count : public Base {
+ static int instances;
+ bool destroyed;
+
+ Count(int n) : Base(n), destroyed(false) { ++instances; }
+ Count(const Count& c) : Base(c), destroyed(false) { ++instances; }
+ ~Count() {
+ BOOST_CHECK(!destroyed); // Detect double-destructor
+ destroyed=true;
+ BOOST_CHECK(--instances >= 0);
+ }
+};
+
+template <class T> int Count<T>::instances = 0;
+
+struct Foo : public Count<Foo> { Foo(int n) : Count<Foo>(n) {}; };
+struct Bar : public Count<Bar> { Bar(int n) : Count<Bar>(n) {}; };
+
+typedef Blob<sizeof(Foo), Base> TestBlob ;
+
+QPID_AUTO_TEST_CASE(testBlobCtor) {
+ {
+ TestBlob empty;
+ BOOST_CHECK(empty.empty());
+ BOOST_CHECK(empty.get() == 0);
+
+ TestBlob empty2(empty);
+ BOOST_CHECK(empty2.empty());
+
+ TestBlob foo(in_place<Foo>(1));
+ BOOST_CHECK(!foo.empty());
+ BOOST_CHECK_EQUAL(1, foo.get()->id);
+ BOOST_CHECK_EQUAL(1, Foo::instances);
+
+ TestBlob foo2(foo);
+ BOOST_CHECK(!foo2.empty());
+ BOOST_CHECK_EQUAL(1, foo2.get()->id);
+ BOOST_CHECK_EQUAL(2, Foo::instances);
+ }
+
+ BOOST_CHECK_EQUAL(0, Foo::instances);
+ BOOST_CHECK_EQUAL(0, Bar::instances);
+}
+
+
+QPID_AUTO_TEST_CASE(testAssign) {
+ {
+ TestBlob b;
+ b = Foo(2);
+ BOOST_CHECK_EQUAL(2, b.get()->id);
+ BOOST_CHECK_EQUAL(1, Foo::instances);
+
+ TestBlob b2(b);
+ BOOST_CHECK_EQUAL(2, b.get()->id);
+ BOOST_CHECK_EQUAL(2, Foo::instances);
+
+ b2 = Bar(3);
+ BOOST_CHECK_EQUAL(3, b2.get()->id);
+ BOOST_CHECK_EQUAL(1, Foo::instances);
+ BOOST_CHECK_EQUAL(1, Bar::instances);
+
+ b2 = in_place<Foo>(4);
+ BOOST_CHECK_EQUAL(4, b2.get()->id);
+ BOOST_CHECK_EQUAL(2, Foo::instances);
+ BOOST_CHECK_EQUAL(0, Bar::instances);
+
+ b2.clear();
+ BOOST_CHECK(b2.empty());
+ BOOST_CHECK_EQUAL(1, Foo::instances);
+ }
+ BOOST_CHECK_EQUAL(0, Foo::instances);
+ BOOST_CHECK_EQUAL(0, Bar::instances);
+}
+
+
+QPID_AUTO_TEST_CASE(testClear) {
+ TestBlob b(in_place<Foo>(5));
+ TestBlob c(b);
+ BOOST_CHECK(!c.empty());
+ BOOST_CHECK(!b.empty());
+ BOOST_CHECK_EQUAL(2, Foo::instances);
+
+ c.clear();
+ BOOST_CHECK(c.empty());
+ BOOST_CHECK_EQUAL(1, Foo::instances);
+
+ b.clear();
+ BOOST_CHECK(b.empty());
+ BOOST_CHECK_EQUAL(0, Foo::instances);
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/BrokerFixture.h b/RC9/qpid/cpp/src/tests/BrokerFixture.h
new file mode 100644
index 0000000000..2a4faa2fd4
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/BrokerFixture.h
@@ -0,0 +1,130 @@
+#ifndef TESTS_BROKERFIXTURE_H
+#define TESTS_BROKERFIXTURE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "SocketProxy.h"
+
+#include "qpid/broker/Broker.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/ConnectionImpl.h"
+#include "qpid/client/Session.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/log/Logger.h"
+#include "qpid/log/Options.h"
+#include "qpid/sys/Thread.h"
+#include <boost/noncopyable.hpp>
+
+/**
+ * A fixture with an in-process broker.
+ */
+struct BrokerFixture : private boost::noncopyable {
+ typedef qpid::broker::Broker Broker;
+ typedef boost::intrusive_ptr<Broker> BrokerPtr;
+
+ BrokerPtr broker;
+ qpid::sys::Thread brokerThread;
+
+ BrokerFixture(Broker::Options opts=Broker::Options()) {
+ // Keep the tests quiet unless logging env. vars have been set by user.
+ if (!::getenv("QPID_LOG_ENABLE") && !::getenv("QPID_TRACE")) {
+ qpid::log::Options logOpts;
+ logOpts.selectors.clear();
+ logOpts.selectors.push_back("error+");
+ qpid::log::Logger::instance().configure(logOpts);
+ }
+ opts.port=0;
+ // Management doesn't play well with multiple in-process brokers.
+ opts.enableMgmt=false;
+ opts.workerThreads=1;
+ opts.dataDir="";
+ opts.auth=false;
+ broker = Broker::create(opts);
+ // TODO aconway 2007-12-05: At one point BrokerFixture
+ // tests could hang in Connection ctor if the following
+ // line is removed. This may not be an issue anymore.
+ broker->getPort(qpid::broker::Broker::TCP_TRANSPORT);
+ brokerThread = qpid::sys::Thread(*broker);
+ };
+
+ ~BrokerFixture() {
+ broker->shutdown();
+ brokerThread.join();
+ }
+
+ /** Open a connection to the broker. */
+ void open(qpid::client::Connection& c) {
+ c.open("localhost", broker->getPort(qpid::broker::Broker::TCP_TRANSPORT));
+ }
+
+ uint16_t getPort() { return broker->getPort(qpid::broker::Broker::TCP_TRANSPORT); }
+};
+
+/** Connection that opens in its constructor */
+struct LocalConnection : public qpid::client::Connection {
+ LocalConnection(uint16_t port) { open("localhost", port); }
+};
+
+/** A local client connection via a socket proxy. */
+struct ProxyConnection : public qpid::client::Connection {
+ SocketProxy proxy;
+ ProxyConnection(int brokerPort) : proxy(brokerPort) {
+ open("localhost", proxy.getPort());
+ }
+ ~ProxyConnection() { close(); }
+};
+
+/** Convenience class to create and open a connection and session
+ * and some related useful objects.
+ */
+template <class ConnectionType=LocalConnection, class SessionType=qpid::client::Session>
+struct ClientT {
+ ConnectionType connection;
+ SessionType session;
+ qpid::client::SubscriptionManager subs;
+ qpid::client::LocalQueue lq;
+ ClientT(uint16_t port, const std::string& name=std::string())
+ : connection(port), session(connection.newSession(name)), subs(session) {}
+
+ ~ClientT() { connection.close(); }
+};
+
+typedef ClientT<> Client;
+
+/**
+ * A BrokerFixture and ready-connected BrokerFixture::Client all in one.
+ */
+template <class ConnectionType, class SessionType=qpid::client::Session>
+struct SessionFixtureT : BrokerFixture, ClientT<ConnectionType,SessionType> {
+
+ SessionFixtureT(Broker::Options opts=Broker::Options()) :
+ BrokerFixture(opts),
+ ClientT<ConnectionType,SessionType>(broker->getPort(qpid::broker::Broker::TCP_TRANSPORT))
+ {}
+
+};
+
+typedef SessionFixtureT<LocalConnection> SessionFixture;
+typedef SessionFixtureT<ProxyConnection> ProxySessionFixture;
+
+
+#endif /*!TESTS_BROKERFIXTURE_H*/
diff --git a/RC9/qpid/cpp/src/tests/ClientSessionTest.cpp b/RC9/qpid/cpp/src/tests/ClientSessionTest.cpp
new file mode 100644
index 0000000000..5d047dcd0e
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/ClientSessionTest.cpp
@@ -0,0 +1,452 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "unit_test.h"
+#include "test_tools.h"
+#include "BrokerFixture.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/sys/Monitor.h"
+#include "qpid/sys/Thread.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/client/Session.h"
+#include "qpid/framing/TransferContent.h"
+#include "qpid/framing/reply_exceptions.h"
+
+#include <boost/optional.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/bind.hpp>
+#include <boost/ptr_container/ptr_vector.hpp>
+
+#include <vector>
+
+QPID_AUTO_TEST_SUITE(ClientSessionTest)
+
+using namespace qpid::client;
+using namespace qpid::framing;
+using namespace qpid;
+using qpid::sys::Monitor;
+using qpid::sys::Thread;
+using qpid::sys::TIME_SEC;
+using qpid::broker::Broker;
+using std::string;
+using std::cout;
+using std::endl;
+
+
+struct DummyListener : public sys::Runnable, public MessageListener {
+ std::vector<Message> messages;
+ string name;
+ uint expected;
+ SubscriptionManager submgr;
+
+ DummyListener(Session& session, const string& n, uint ex) :
+ name(n), expected(ex), submgr(session) {}
+
+ void run()
+ {
+ submgr.subscribe(*this, name);
+ submgr.run();
+ }
+
+ void received(Message& msg)
+ {
+ messages.push_back(msg);
+ if (--expected == 0) {
+ submgr.stop();
+ }
+ }
+};
+
+struct SimpleListener : public MessageListener
+{
+ Monitor lock;
+ std::vector<Message> messages;
+
+ void received(Message& msg)
+ {
+ Monitor::ScopedLock l(lock);
+ messages.push_back(msg);
+ lock.notifyAll();
+ }
+
+ void waitFor(const uint n)
+ {
+ Monitor::ScopedLock l(lock);
+ while (messages.size() < n) {
+ lock.wait();
+ }
+ }
+};
+
+struct ClientSessionFixture : public ProxySessionFixture
+{
+ ClientSessionFixture(Broker::Options opts = Broker::Options()) : ProxySessionFixture(opts) {
+ session.queueDeclare(arg::queue="my-queue");
+ }
+};
+
+QPID_AUTO_TEST_CASE(testQueueQuery) {
+ ClientSessionFixture fix;
+ fix.session = fix.connection.newSession();
+ fix.session.queueDeclare(arg::queue="q", arg::alternateExchange="amq.fanout",
+ arg::exclusive=true, arg::autoDelete=true);
+ QueueQueryResult result = fix.session.queueQuery("q");
+ BOOST_CHECK_EQUAL(false, result.getDurable());
+ BOOST_CHECK_EQUAL(true, result.getExclusive());
+ BOOST_CHECK_EQUAL("amq.fanout", result.getAlternateExchange());
+}
+
+QPID_AUTO_TEST_CASE(testDispatcher)
+{
+ ClientSessionFixture fix;
+ fix.session =fix.connection.newSession();
+ size_t count = 100;
+ for (size_t i = 0; i < count; ++i)
+ fix.session.messageTransfer(arg::content=TransferContent(boost::lexical_cast<string>(i), "my-queue"));
+ DummyListener listener(fix.session, "my-queue", count);
+ listener.run();
+ BOOST_CHECK_EQUAL(count, listener.messages.size());
+ for (size_t i = 0; i < count; ++i)
+ BOOST_CHECK_EQUAL(boost::lexical_cast<string>(i), listener.messages[i].getData());
+}
+
+QPID_AUTO_TEST_CASE(testDispatcherThread)
+{
+ ClientSessionFixture fix;
+ fix.session =fix.connection.newSession();
+ size_t count = 10;
+ DummyListener listener(fix.session, "my-queue", count);
+ sys::Thread t(listener);
+ for (size_t i = 0; i < count; ++i) {
+ fix.session.messageTransfer(arg::content=TransferContent(boost::lexical_cast<string>(i), "my-queue"));
+ }
+ t.join();
+ BOOST_CHECK_EQUAL(count, listener.messages.size());
+ for (size_t i = 0; i < count; ++i)
+ BOOST_CHECK_EQUAL(boost::lexical_cast<string>(i), listener.messages[i].getData());
+}
+
+QPID_AUTO_TEST_CASE_EXPECTED_FAILURES(testSuspend0Timeout, 1)
+{
+ ClientSessionFixture fix;
+ fix.session.suspend(); // session has 0 timeout.
+ try {
+ fix.connection.resume(fix.session);
+ BOOST_FAIL("Expected InvalidArgumentException.");
+ } catch(const InternalErrorException&) {}
+}
+
+QPID_AUTO_TEST_CASE(testUseSuspendedError)
+{
+ ClientSessionFixture fix;
+ fix.session.timeout(60);
+ fix.session.suspend();
+ try {
+ fix.session.exchangeQuery(arg::exchange="amq.fanout");
+ BOOST_FAIL("Expected session suspended exception");
+ } catch(const NotAttachedException&) {}
+}
+
+QPID_AUTO_TEST_CASE_EXPECTED_FAILURES(testSuspendResume, 1)
+{
+ ClientSessionFixture fix;
+ fix.session.timeout(60);
+ fix.session.suspend();
+ // Make sure we are still subscribed after resume.
+ fix.connection.resume(fix.session);
+ fix.session.messageTransfer(arg::content=TransferContent("my-message", "my-queue"));
+ FrameSet::shared_ptr msg = fix.session.get();
+ BOOST_CHECK_EQUAL(string("my-message"), msg->getContent());
+}
+
+
+QPID_AUTO_TEST_CASE(testSendToSelf) {
+ ClientSessionFixture fix;
+ SimpleListener mylistener;
+ fix.session.queueDeclare(arg::queue="myq", arg::exclusive=true, arg::autoDelete=true);
+ fix.subs.subscribe(mylistener, "myq");
+ sys::Thread runner(fix.subs);//start dispatcher thread
+ string data("msg");
+ Message msg(data, "myq");
+ const uint count=10;
+ for (uint i = 0; i < count; ++i) {
+ fix.session.messageTransfer(arg::content=msg);
+ }
+ mylistener.waitFor(count);
+ fix.subs.cancel("myq");
+ fix.subs.stop();
+ runner.join();
+ fix.session.close();
+ BOOST_CHECK_EQUAL(mylistener.messages.size(), count);
+ for (uint j = 0; j < count; ++j) {
+ BOOST_CHECK_EQUAL(mylistener.messages[j].getData(), data);
+ }
+}
+
+QPID_AUTO_TEST_CASE(testLocalQueue) {
+ ClientSessionFixture fix;
+ fix.session.queueDeclare(arg::queue="lq", arg::exclusive=true, arg::autoDelete=true);
+ LocalQueue lq;
+ fix.subs.subscribe(lq, "lq", FlowControl(2, FlowControl::UNLIMITED, false));
+ fix.session.messageTransfer(arg::content=Message("foo0", "lq"));
+ fix.session.messageTransfer(arg::content=Message("foo1", "lq"));
+ fix.session.messageTransfer(arg::content=Message("foo2", "lq"));
+ BOOST_CHECK_EQUAL("foo0", lq.pop().getData());
+ BOOST_CHECK_EQUAL("foo1", lq.pop().getData());
+ BOOST_CHECK(lq.empty()); // Credit exhausted.
+ fix.subs.getSubscription("lq").setFlowControl(FlowControl::unlimited());
+ BOOST_CHECK_EQUAL("foo2", lq.pop().getData());
+}
+
+struct DelayedTransfer : sys::Runnable
+{
+ ClientSessionFixture& fixture;
+
+ DelayedTransfer(ClientSessionFixture& f) : fixture(f) {}
+
+ void run()
+ {
+ sleep(1);
+ fixture.session.messageTransfer(arg::content=Message("foo2", "getq"));
+ }
+};
+
+QPID_AUTO_TEST_CASE(testGet) {
+ ClientSessionFixture fix;
+ fix.session.queueDeclare(arg::queue="getq", arg::exclusive=true, arg::autoDelete=true);
+ fix.session.messageTransfer(arg::content=Message("foo0", "getq"));
+ fix.session.messageTransfer(arg::content=Message("foo1", "getq"));
+ Message got;
+ BOOST_CHECK(fix.subs.get(got, "getq", TIME_SEC));
+ BOOST_CHECK_EQUAL("foo0", got.getData());
+ BOOST_CHECK(fix.subs.get(got, "getq", TIME_SEC));
+ BOOST_CHECK_EQUAL("foo1", got.getData());
+ BOOST_CHECK(!fix.subs.get(got, "getq"));
+ DelayedTransfer sender(fix);
+ Thread t(sender);
+ //test timed get where message shows up after a short delay
+ BOOST_CHECK(fix.subs.get(got, "getq", 5*TIME_SEC));
+ BOOST_CHECK_EQUAL("foo2", got.getData());
+ t.join();
+}
+
+QPID_AUTO_TEST_CASE(testOpenFailure) {
+ BrokerFixture b;
+ Connection c;
+ string host("unknowable-host");
+ try {
+ c.open(host);
+ } catch (const Exception&) {
+ BOOST_CHECK(!c.isOpen());
+ }
+ b.open(c);
+ BOOST_CHECK(c.isOpen());
+ c.close();
+ BOOST_CHECK(!c.isOpen());
+}
+
+QPID_AUTO_TEST_CASE(testPeriodicExpiration) {
+ Broker::Options opts;
+ opts.queueCleanInterval = 1;
+ ClientSessionFixture fix(opts);
+ fix.session.queueDeclare(arg::queue="my-queue", arg::exclusive=true, arg::autoDelete=true);
+
+ for (uint i = 0; i < 10; i++) {
+ Message m((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
+ if (i % 2) m.getDeliveryProperties().setTtl(500);
+ fix.session.messageTransfer(arg::content=m);
+ }
+
+ BOOST_CHECK_EQUAL(fix.session.queueQuery(string("my-queue")).getMessageCount(), 10u);
+ sleep(2);
+ BOOST_CHECK_EQUAL(fix.session.queueQuery(string("my-queue")).getMessageCount(), 5u);
+}
+
+QPID_AUTO_TEST_CASE(testExpirationOnPop) {
+ ClientSessionFixture fix;
+ fix.session.queueDeclare(arg::queue="my-queue", arg::exclusive=true, arg::autoDelete=true);
+
+ for (uint i = 0; i < 10; i++) {
+ Message m((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
+ if (i % 2) m.getDeliveryProperties().setTtl(200);
+ fix.session.messageTransfer(arg::content=m);
+ }
+
+ ::usleep(300* 1000);
+
+ for (uint i = 0; i < 10; i++) {
+ if (i % 2) continue;
+ Message m;
+ BOOST_CHECK(fix.subs.get(m, "my-queue", TIME_SEC));
+ BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i+1)).str(), m.getData());
+ }
+}
+
+QPID_AUTO_TEST_CASE(testRelease) {
+ ClientSessionFixture fix;
+
+ const uint count=10;
+ for (uint i = 0; i < count; i++) {
+ Message m((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
+ fix.session.messageTransfer(arg::content=m);
+ }
+
+ fix.subs.setAutoStop(false);
+ fix.subs.start();
+ SubscriptionSettings settings;
+ settings.autoAck = 0;
+
+ SimpleListener l1;
+ Subscription s1 = fix.subs.subscribe(l1, "my-queue", settings);
+ l1.waitFor(count);
+ s1.cancel();
+
+ for (uint i = 0; i < count; i++) {
+ BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i+1)).str(), l1.messages[i].getData());
+ }
+ s1.release(s1.getUnaccepted());
+
+ //check that released messages are redelivered
+ settings.autoAck = 1;
+ SimpleListener l2;
+ Subscription s2 = fix.subs.subscribe(l2, "my-queue", settings);
+ l2.waitFor(count);
+ for (uint i = 0; i < count; i++) {
+ BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i+1)).str(), l2.messages[i].getData());
+ }
+
+ fix.subs.stop();
+ fix.subs.wait();
+ fix.session.close();
+}
+
+QPID_AUTO_TEST_CASE(testCompleteOnAccept) {
+ ClientSessionFixture fix;
+ const uint count = 8;
+ const uint chunk = 4;
+ for (uint i = 0; i < count; i++) {
+ Message m((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
+ fix.session.messageTransfer(arg::content=m);
+ }
+
+ SubscriptionSettings settings;
+ settings.autoAck = 0;
+ settings.completionMode = COMPLETE_ON_ACCEPT;
+ settings.flowControl = FlowControl::messageWindow(chunk);
+
+ LocalQueue q;
+ Subscription s = fix.subs.subscribe(q, "my-queue", settings);
+ fix.session.messageFlush(arg::destination=s.getName());
+ SequenceSet accepted;
+ for (uint i = 0; i < chunk; i++) {
+ Message m;
+ BOOST_CHECK(q.get(m));
+ BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i+1)).str(), m.getData());
+ accepted.add(m.getId());
+ }
+ Message m;
+ BOOST_CHECK(!q.get(m));
+
+ s.accept(accepted);
+ fix.session.messageFlush(arg::destination=s.getName());
+ accepted.clear();
+
+ for (uint i = chunk; i < count; i++) {
+ Message m;
+ BOOST_CHECK(q.get(m));
+ BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i+1)).str(), m.getData());
+ accepted.add(m.getId());
+ }
+ fix.session.messageAccept(accepted);
+}
+
+namespace
+{
+struct Publisher : qpid::sys::Runnable
+{
+ AsyncSession session;
+ Message message;
+ uint count;
+ Thread thread;
+
+ Publisher(Connection& con, Message m, uint c) : session(con.newSession()), message(m), count(c) {}
+
+ void start()
+ {
+ thread = Thread(*this);
+ }
+
+ void join()
+ {
+ thread.join();
+ }
+
+ void run()
+ {
+ for (uint i = 0; i < count; i++) {
+ session.messageTransfer(arg::content=message);
+ }
+ session.sync();
+ session.close();
+ }
+};
+}
+
+QPID_AUTO_TEST_CASE(testConcurrentSenders)
+{
+ //Ensure concurrent publishing sessions on a connection don't
+ //cause assertions, deadlocks or other undesirables:
+ BrokerFixture fix;
+ Connection connection;
+ ConnectionSettings settings;
+ settings.maxFrameSize = 1024;
+ settings.port = fix.broker->getPort(qpid::broker::Broker::TCP_TRANSPORT);
+ connection.open(settings);
+ AsyncSession session = connection.newSession();
+ Message message(string(512, 'X'));
+
+ boost::ptr_vector<Publisher> publishers;
+ for (size_t i = 0; i < 5; i++) {
+ publishers.push_back(new Publisher(connection, message, 100));
+ }
+ for_each(publishers.begin(), publishers.end(), boost::bind(&Publisher::start, _1));
+ for_each(publishers.begin(), publishers.end(), boost::bind(&Publisher::join, _1));
+ connection.close();
+}
+
+
+QPID_AUTO_TEST_CASE(testExclusiveSubscribe)
+{
+ ClientSessionFixture fix;
+ fix.session.queueDeclare(arg::queue="myq", arg::exclusive=true, arg::autoDelete=true);
+ SubscriptionSettings settings;
+ settings.exclusive = true;
+ LocalQueue q;
+ fix.subs.subscribe(q, "myq", settings, "first");
+ //attempt to create new subscriber should fail
+ ScopedSuppressLogging sl;
+ BOOST_CHECK_THROW(fix.subs.subscribe(q, "myq", "second"), ResourceLockedException);
+ ;
+
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+
diff --git a/RC9/qpid/cpp/src/tests/ConnectionOptions.h b/RC9/qpid/cpp/src/tests/ConnectionOptions.h
new file mode 100644
index 0000000000..0130842668
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/ConnectionOptions.h
@@ -0,0 +1,54 @@
+#ifndef QPID_CLIENT_CONNECTIONOPTIONS_H
+#define QPID_CLIENT_CONNECTIONOPTIONS_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/client/ConnectionSettings.h"
+#include "qpid/Options.h"
+
+/**
+ * Options parser for ConnectionOptions.
+ */
+struct ConnectionOptions : public qpid::Options,
+ public qpid::client::ConnectionSettings
+{
+ ConnectionOptions() : qpid::Options("Connection Settings")
+ {
+ using namespace qpid;
+ addOptions()
+ ("broker,b", optValue(host, "HOST"), "Broker host to connect to")
+ ("port,p", optValue(port, "PORT"), "Broker port to connect to")
+ ("protocol,P", optValue(protocol, "tcp|rdma"), "Protocol to use for broker connection")
+ ("virtualhost,v", optValue(virtualhost, "VHOST"), "virtual host")
+ ("username", optValue(username, "USER"), "user name for broker log in.")
+ ("password", optValue(password, "PASSWORD"), "password for broker log in.")
+ ("mechanism", optValue(mechanism, "MECH"), "SASL mechanism to use when authenticating.")
+ ("locale", optValue(locale, "LOCALE"), "locale to use.")
+ ("max-channels", optValue(maxChannels, "N"), "the maximum number of channels the client requires.")
+ ("max-frame-size", optValue(maxFrameSize, "N"), "the maximum frame size to request.")
+ ("bounds-multiplier", optValue(bounds, "N"),
+ "bound size of write queue (as a multiple of the max frame size).")
+ ("tcp-nodelay", optValue(tcpNoDelay), "Turn on tcp-nodelay");
+ }
+};
+
+#endif /*!QPID_CLIENT_CONNECTIONOPTIONS_H*/
diff --git a/RC9/qpid/cpp/src/tests/ConsoleTest.cpp b/RC9/qpid/cpp/src/tests/ConsoleTest.cpp
new file mode 100644
index 0000000000..1d55b13f3c
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/ConsoleTest.cpp
@@ -0,0 +1,43 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/console/Package.h"
+#include "qpid/console/ClassKey.h"
+#include "unit_test.h"
+
+QPID_AUTO_TEST_SUITE(ConsoleTestSuite)
+
+using namespace qpid::framing;
+using namespace qpid::console;
+
+QPID_AUTO_TEST_CASE(testClassKey) {
+ uint8_t hash[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+ ClassKey k("com.redhat.test", "class", hash);
+
+ BOOST_CHECK_EQUAL(k.getPackageName(), "com.redhat.test");
+ BOOST_CHECK_EQUAL(k.getClassName(), "class");
+ BOOST_CHECK_EQUAL(k.getHashString(), "00010203-04050607-08090a0b-0c0d0e0f");
+ BOOST_CHECK_EQUAL(k.str(), "com.redhat.test:class(00010203-04050607-08090a0b-0c0d0e0f)");
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+
diff --git a/RC9/qpid/cpp/src/tests/DeliveryRecordTest.cpp b/RC9/qpid/cpp/src/tests/DeliveryRecordTest.cpp
new file mode 100644
index 0000000000..47c7157749
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/DeliveryRecordTest.cpp
@@ -0,0 +1,62 @@
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/broker/DeliveryRecord.h"
+#include "unit_test.h"
+#include <iostream>
+#include <memory>
+#include <boost/format.hpp>
+
+using namespace qpid::broker;
+using namespace qpid::sys;
+using namespace qpid::framing;
+using boost::dynamic_pointer_cast;
+using std::list;
+
+QPID_AUTO_TEST_SUITE(DeliveryRecordTestSuite)
+
+QPID_AUTO_TEST_CASE(testSort)
+{
+ list<SequenceNumber> ids;
+ ids.push_back(SequenceNumber(6));
+ ids.push_back(SequenceNumber(2));
+ ids.push_back(SequenceNumber(4));
+ ids.push_back(SequenceNumber(5));
+ ids.push_back(SequenceNumber(1));
+ ids.push_back(SequenceNumber(3));
+
+ list<DeliveryRecord> records;
+ for (list<SequenceNumber>::iterator i = ids.begin(); i != ids.end(); i++) {
+ DeliveryRecord r(QueuedMessage(0), Queue::shared_ptr(), "tag", false, false, false);
+ r.setId(*i);
+ records.push_back(r);
+ }
+ records.sort();
+
+ SequenceNumber expected(0);
+ for (list<DeliveryRecord>::iterator i = records.begin(); i != records.end(); i++) {
+ BOOST_CHECK(i->matches(++expected));
+ }
+}
+
+
+QPID_AUTO_TEST_SUITE_END()
+
diff --git a/RC9/qpid/cpp/src/tests/DispatcherTest.cpp b/RC9/qpid/cpp/src/tests/DispatcherTest.cpp
new file mode 100644
index 0000000000..7631956acc
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/DispatcherTest.cpp
@@ -0,0 +1,128 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Poller.h"
+#include "qpid/sys/Dispatcher.h"
+#include "qpid/sys/Thread.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <iostream>
+#include <boost/bind.hpp>
+
+using namespace std;
+using namespace qpid::sys;
+
+int writeALot(int fd, const string& s) {
+ int bytesWritten = 0;
+ do {
+ errno = 0;
+ int lastWrite = ::write(fd, s.c_str(), s.size());
+ if ( lastWrite >= 0) {
+ bytesWritten += lastWrite;
+ }
+ } while (errno != EAGAIN);
+ return bytesWritten;
+}
+
+int readALot(int fd) {
+ int bytesRead = 0;
+ char buf[10240];
+
+ do {
+ errno = 0;
+ int lastRead = ::read(fd, buf, sizeof(buf));
+ if ( lastRead >= 0) {
+ bytesRead += lastRead;
+ }
+ } while (errno != EAGAIN);
+ return bytesRead;
+}
+
+int64_t writtenBytes = 0;
+int64_t readBytes = 0;
+
+void writer(DispatchHandle& h, int fd, const string& s) {
+ writtenBytes += writeALot(fd, s);
+ h.rewatch();
+}
+
+void reader(DispatchHandle& h, int fd) {
+ readBytes += readALot(fd);
+ h.rewatch();
+}
+
+int main(int argc, char** argv)
+{
+ // Create poller
+ Poller::shared_ptr poller(new Poller);
+
+ // Create dispatcher thread
+ Dispatcher d(poller);
+ Dispatcher d1(poller);
+ //Dispatcher d2(poller);
+ //Dispatcher d3(poller);
+ Thread dt(d);
+ Thread dt1(d1);
+ //Thread dt2(d2);
+ //Thread dt3(d3);
+
+ // Setup sender and receiver
+ int sv[2];
+ int rc = ::socketpair(AF_LOCAL, SOCK_STREAM, 0, sv);
+ assert(rc >= 0);
+
+ // Set non-blocking
+ rc = ::fcntl(sv[0], F_SETFL, O_NONBLOCK);
+ assert(rc >= 0);
+
+ rc = ::fcntl(sv[1], F_SETFL, O_NONBLOCK);
+ assert(rc >= 0);
+
+ // Make up a large string
+ string testString = "This is only a test ... 1,2,3,4,5,6,7,8,9,10;";
+ for (int i = 0; i < 8; i++)
+ testString += testString;
+
+ DispatchHandle rh(sv[0], boost::bind(reader, _1, sv[0]), 0);
+ DispatchHandle wh(sv[1], 0, boost::bind(writer, _1, sv[1], testString));
+
+ rh.watch(poller);
+ wh.watch(poller);
+
+ // wait 2 minutes then shutdown
+ sleep(60);
+
+ poller->shutdown();
+ dt.join();
+ dt1.join();
+ //dt2.join();
+ //dt3.join();
+
+ cout << "Wrote: " << writtenBytes << "\n";
+ cout << "Read: " << readBytes << "\n";
+
+ return 0;
+}
diff --git a/RC9/qpid/cpp/src/tests/DtxWorkRecordTest.cpp b/RC9/qpid/cpp/src/tests/DtxWorkRecordTest.cpp
new file mode 100644
index 0000000000..c7c1b460ff
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/DtxWorkRecordTest.cpp
@@ -0,0 +1,189 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/broker/DtxWorkRecord.h"
+#include "unit_test.h"
+#include <iostream>
+#include <vector>
+#include "TxMocks.h"
+
+using namespace qpid::broker;
+using boost::static_pointer_cast;
+
+QPID_AUTO_TEST_SUITE(DtxWorkRecordTestSuite)
+
+QPID_AUTO_TEST_CASE(testOnePhaseCommit){
+ MockTransactionalStore store;
+ store.expectBegin().expectCommit();
+
+ MockTxOp::shared_ptr opA(new MockTxOp());
+ opA->expectPrepare().expectCommit();
+ MockTxOp::shared_ptr opB(new MockTxOp());
+ opB->expectPrepare().expectCommit();
+
+ DtxBuffer::shared_ptr bufferA(new DtxBuffer());
+ bufferA->enlist(static_pointer_cast<TxOp>(opA));
+ bufferA->markEnded();
+ DtxBuffer::shared_ptr bufferB(new DtxBuffer());
+ bufferB->enlist(static_pointer_cast<TxOp>(opB));
+ bufferB->markEnded();
+
+ DtxWorkRecord work("my-xid", &store);
+ work.add(bufferA);
+ work.add(bufferB);
+
+ work.commit(true);
+
+ store.check();
+ BOOST_CHECK(store.isCommitted());
+ opA->check();
+ opB->check();
+}
+
+QPID_AUTO_TEST_CASE(testFailOnOnePhaseCommit){
+ MockTransactionalStore store;
+ store.expectBegin().expectAbort();
+
+ MockTxOp::shared_ptr opA(new MockTxOp());
+ opA->expectPrepare().expectRollback();
+ MockTxOp::shared_ptr opB(new MockTxOp(true));
+ opB->expectPrepare().expectRollback();
+ MockTxOp::shared_ptr opC(new MockTxOp());
+ opC->expectRollback();
+
+ DtxBuffer::shared_ptr bufferA(new DtxBuffer());
+ bufferA->enlist(static_pointer_cast<TxOp>(opA));
+ bufferA->markEnded();
+ DtxBuffer::shared_ptr bufferB(new DtxBuffer());
+ bufferB->enlist(static_pointer_cast<TxOp>(opB));
+ bufferB->markEnded();
+ DtxBuffer::shared_ptr bufferC(new DtxBuffer());
+ bufferC->enlist(static_pointer_cast<TxOp>(opC));
+ bufferC->markEnded();
+
+ DtxWorkRecord work("my-xid", &store);
+ work.add(bufferA);
+ work.add(bufferB);
+ work.add(bufferC);
+
+ work.commit(true);
+
+ BOOST_CHECK(store.isAborted());
+ store.check();
+
+ opA->check();
+ opB->check();
+ opC->check();
+}
+
+QPID_AUTO_TEST_CASE(testTwoPhaseCommit){
+ MockTransactionalStore store;
+ store.expectBegin2PC().expectPrepare().expectCommit();
+
+ MockTxOp::shared_ptr opA(new MockTxOp());
+ opA->expectPrepare().expectCommit();
+ MockTxOp::shared_ptr opB(new MockTxOp());
+ opB->expectPrepare().expectCommit();
+
+ DtxBuffer::shared_ptr bufferA(new DtxBuffer());
+ bufferA->enlist(static_pointer_cast<TxOp>(opA));
+ bufferA->markEnded();
+ DtxBuffer::shared_ptr bufferB(new DtxBuffer());
+ bufferB->enlist(static_pointer_cast<TxOp>(opB));
+ bufferB->markEnded();
+
+ DtxWorkRecord work("my-xid", &store);
+ work.add(bufferA);
+ work.add(bufferB);
+
+ BOOST_CHECK(work.prepare());
+ BOOST_CHECK(store.isPrepared());
+ work.commit(false);
+ store.check();
+ BOOST_CHECK(store.isCommitted());
+ opA->check();
+ opB->check();
+}
+
+QPID_AUTO_TEST_CASE(testFailOnTwoPhaseCommit){
+ MockTransactionalStore store;
+ store.expectBegin2PC().expectAbort();
+
+ MockTxOp::shared_ptr opA(new MockTxOp());
+ opA->expectPrepare().expectRollback();
+ MockTxOp::shared_ptr opB(new MockTxOp(true));
+ opB->expectPrepare().expectRollback();
+ MockTxOp::shared_ptr opC(new MockTxOp());
+ opC->expectRollback();
+
+ DtxBuffer::shared_ptr bufferA(new DtxBuffer());
+ bufferA->enlist(static_pointer_cast<TxOp>(opA));
+ bufferA->markEnded();
+ DtxBuffer::shared_ptr bufferB(new DtxBuffer());
+ bufferB->enlist(static_pointer_cast<TxOp>(opB));
+ bufferB->markEnded();
+ DtxBuffer::shared_ptr bufferC(new DtxBuffer());
+ bufferC->enlist(static_pointer_cast<TxOp>(opC));
+ bufferC->markEnded();
+
+ DtxWorkRecord work("my-xid", &store);
+ work.add(bufferA);
+ work.add(bufferB);
+ work.add(bufferC);
+
+ BOOST_CHECK(!work.prepare());
+ BOOST_CHECK(store.isAborted());
+ store.check();
+ opA->check();
+ opB->check();
+ opC->check();
+}
+
+QPID_AUTO_TEST_CASE(testRollback){
+ MockTransactionalStore store;
+ store.expectBegin2PC().expectPrepare().expectAbort();
+
+ MockTxOp::shared_ptr opA(new MockTxOp());
+ opA->expectPrepare().expectRollback();
+ MockTxOp::shared_ptr opB(new MockTxOp());
+ opB->expectPrepare().expectRollback();
+
+ DtxBuffer::shared_ptr bufferA(new DtxBuffer());
+ bufferA->enlist(static_pointer_cast<TxOp>(opA));
+ bufferA->markEnded();
+ DtxBuffer::shared_ptr bufferB(new DtxBuffer());
+ bufferB->enlist(static_pointer_cast<TxOp>(opB));
+ bufferB->markEnded();
+
+ DtxWorkRecord work("my-xid", &store);
+ work.add(bufferA);
+ work.add(bufferB);
+
+ BOOST_CHECK(work.prepare());
+ BOOST_CHECK(store.isPrepared());
+ work.rollback();
+ store.check();
+ BOOST_CHECK(store.isAborted());
+ opA->check();
+ opB->check();
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
diff --git a/RC9/qpid/cpp/src/tests/ExchangeTest.cpp b/RC9/qpid/cpp/src/tests/ExchangeTest.cpp
new file mode 100644
index 0000000000..0946d3115d
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/ExchangeTest.cpp
@@ -0,0 +1,284 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/Exception.h"
+#include "qpid/broker/Exchange.h"
+#include "qpid/broker/Queue.h"
+#include "qpid/broker/DeliverableMessage.h"
+#include "qpid/broker/DirectExchange.h"
+#include "qpid/broker/ExchangeRegistry.h"
+#include "qpid/broker/FanOutExchange.h"
+#include "qpid/broker/HeadersExchange.h"
+#include "qpid/broker/TopicExchange.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "unit_test.h"
+#include <iostream>
+#include "MessageUtils.h"
+
+using boost::intrusive_ptr;
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::sys;
+using namespace qpid;
+
+QPID_AUTO_TEST_SUITE(ExchangeTestSuite)
+
+QPID_AUTO_TEST_CASE(testMe)
+{
+ Queue::shared_ptr queue(new Queue("queue", true));
+ Queue::shared_ptr queue2(new Queue("queue2", true));
+
+ TopicExchange topic("topic");
+ topic.bind(queue, "abc", 0);
+ topic.bind(queue2, "abc", 0);
+
+ DirectExchange direct("direct");
+ direct.bind(queue, "abc", 0);
+ direct.bind(queue2, "abc", 0);
+
+ queue.reset();
+ queue2.reset();
+
+ intrusive_ptr<Message> msgPtr(MessageUtils::createMessage("exchange", "key", "id"));
+ DeliverableMessage msg(msgPtr);
+ topic.route(msg, "abc", 0);
+ direct.route(msg, "abc", 0);
+
+}
+
+QPID_AUTO_TEST_CASE(testIsBound)
+{
+ Queue::shared_ptr a(new Queue("a", true));
+ Queue::shared_ptr b(new Queue("b", true));
+ Queue::shared_ptr c(new Queue("c", true));
+ Queue::shared_ptr d(new Queue("d", true));
+
+ string k1("abc");
+ string k2("def");
+ string k3("xyz");
+
+ FanOutExchange fanout("fanout");
+ BOOST_CHECK(fanout.bind(a, "", 0));
+ BOOST_CHECK(fanout.bind(b, "", 0));
+ BOOST_CHECK(fanout.bind(c, "", 0));
+
+ BOOST_CHECK(fanout.isBound(a, 0, 0));
+ BOOST_CHECK(fanout.isBound(b, 0, 0));
+ BOOST_CHECK(fanout.isBound(c, 0, 0));
+ BOOST_CHECK(!fanout.isBound(d, 0, 0));
+
+ DirectExchange direct("direct");
+ BOOST_CHECK(direct.bind(a, k1, 0));
+ BOOST_CHECK(direct.bind(a, k3, 0));
+ BOOST_CHECK(direct.bind(b, k2, 0));
+ BOOST_CHECK(direct.bind(c, k1, 0));
+
+ BOOST_CHECK(direct.isBound(a, 0, 0));
+ BOOST_CHECK(direct.isBound(a, &k1, 0));
+ BOOST_CHECK(direct.isBound(a, &k3, 0));
+ BOOST_CHECK(!direct.isBound(a, &k2, 0));
+ BOOST_CHECK(direct.isBound(b, 0, 0));
+ BOOST_CHECK(direct.isBound(b, &k2, 0));
+ BOOST_CHECK(direct.isBound(c, &k1, 0));
+ BOOST_CHECK(!direct.isBound(d, 0, 0));
+ BOOST_CHECK(!direct.isBound(d, &k1, 0));
+ BOOST_CHECK(!direct.isBound(d, &k2, 0));
+ BOOST_CHECK(!direct.isBound(d, &k3, 0));
+
+ TopicExchange topic("topic");
+ BOOST_CHECK(topic.bind(a, k1, 0));
+ BOOST_CHECK(topic.bind(a, k3, 0));
+ BOOST_CHECK(topic.bind(b, k2, 0));
+ BOOST_CHECK(topic.bind(c, k1, 0));
+
+ BOOST_CHECK(topic.isBound(a, 0, 0));
+ BOOST_CHECK(topic.isBound(a, &k1, 0));
+ BOOST_CHECK(topic.isBound(a, &k3, 0));
+ BOOST_CHECK(!topic.isBound(a, &k2, 0));
+ BOOST_CHECK(topic.isBound(b, 0, 0));
+ BOOST_CHECK(topic.isBound(b, &k2, 0));
+ BOOST_CHECK(topic.isBound(c, &k1, 0));
+ BOOST_CHECK(!topic.isBound(d, 0, 0));
+ BOOST_CHECK(!topic.isBound(d, &k1, 0));
+ BOOST_CHECK(!topic.isBound(d, &k2, 0));
+ BOOST_CHECK(!topic.isBound(d, &k3, 0));
+
+ HeadersExchange headers("headers");
+ FieldTable args1;
+ args1.setString("x-match", "all");
+ args1.setString("a", "A");
+ args1.setInt("b", 1);
+ FieldTable args2;
+ args2.setString("x-match", "any");
+ args2.setString("a", "A");
+ args2.setInt("b", 1);
+ FieldTable args3;
+ args3.setString("x-match", "any");
+ args3.setString("c", "C");
+ args3.setInt("b", 6);
+
+ headers.bind(a, "", &args1);
+ headers.bind(a, "", &args3);
+ headers.bind(b, "", &args2);
+ headers.bind(c, "", &args1);
+
+ BOOST_CHECK(headers.isBound(a, 0, 0));
+ BOOST_CHECK(headers.isBound(a, 0, &args1));
+ BOOST_CHECK(headers.isBound(a, 0, &args3));
+ BOOST_CHECK(!headers.isBound(a, 0, &args2));
+ BOOST_CHECK(headers.isBound(b, 0, 0));
+ BOOST_CHECK(headers.isBound(b, 0, &args2));
+ BOOST_CHECK(headers.isBound(c, 0, &args1));
+ BOOST_CHECK(!headers.isBound(d, 0, 0));
+ BOOST_CHECK(!headers.isBound(d, 0, &args1));
+ BOOST_CHECK(!headers.isBound(d, 0, &args2));
+ BOOST_CHECK(!headers.isBound(d, 0, &args3));
+}
+
+QPID_AUTO_TEST_CASE(testDeleteGetAndRedeclare)
+{
+ ExchangeRegistry exchanges;
+ exchanges.declare("my-exchange", "direct", false, FieldTable());
+ exchanges.destroy("my-exchange");
+ try {
+ exchanges.get("my-exchange");
+ } catch (const NotFoundException&) {}
+ std::pair<Exchange::shared_ptr, bool> response = exchanges.declare("my-exchange", "direct", false, FieldTable());
+ BOOST_CHECK_EQUAL(string("direct"), response.first->getType());
+}
+
+intrusive_ptr<Message> cmessage(std::string exchange, std::string routingKey) {
+ intrusive_ptr<Message> msg(new Message());
+ AMQFrame method(in_place<MessageTransferBody>(ProtocolVersion(), exchange, 0, 0));
+ AMQFrame header(in_place<AMQHeaderBody>());
+ msg->getFrames().append(method);
+ msg->getFrames().append(header);
+ msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setRoutingKey(routingKey);
+ return msg;
+}
+
+QPID_AUTO_TEST_CASE(testSequenceOptions)
+{
+ FieldTable args;
+ args.setInt("qpid.msg_sequence",1);
+ char* buff = new char[10000];
+ framing::Buffer buffer(buff,10000);
+ {
+ DirectExchange direct("direct1", false, args);
+
+ intrusive_ptr<Message> msg1 = cmessage("e", "A");
+ intrusive_ptr<Message> msg2 = cmessage("e", "B");
+ intrusive_ptr<Message> msg3 = cmessage("e", "C");
+
+ DeliverableMessage dmsg1(msg1);
+ DeliverableMessage dmsg2(msg2);
+ DeliverableMessage dmsg3(msg3);
+
+ direct.route(dmsg1, "abc", 0);
+ direct.route(dmsg2, "abc", 0);
+ direct.route(dmsg3, "abc", 0);
+
+ BOOST_CHECK_EQUAL(1, msg1->getApplicationHeaders()->getAsInt64("qpid.msg_sequence"));
+ BOOST_CHECK_EQUAL(2, msg2->getApplicationHeaders()->getAsInt64("qpid.msg_sequence"));
+ BOOST_CHECK_EQUAL(3, msg3->getApplicationHeaders()->getAsInt64("qpid.msg_sequence"));
+
+ FanOutExchange fanout("fanout1", false, args);
+ HeadersExchange header("headers1", false, args);
+ TopicExchange topic ("topic1", false, args);
+
+ // check other exchanges, that they preroute
+ intrusive_ptr<Message> msg4 = cmessage("e", "A");
+ intrusive_ptr<Message> msg5 = cmessage("e", "B");
+ intrusive_ptr<Message> msg6 = cmessage("e", "C");
+
+ DeliverableMessage dmsg4(msg4);
+ DeliverableMessage dmsg5(msg5);
+ DeliverableMessage dmsg6(msg6);
+
+ fanout.route(dmsg4, "abc", 0);
+ BOOST_CHECK_EQUAL(1, msg4->getApplicationHeaders()->getAsInt64("qpid.msg_sequence"));
+
+ FieldTable headers;
+ header.route(dmsg5, "abc", &headers);
+ BOOST_CHECK_EQUAL(1, msg5->getApplicationHeaders()->getAsInt64("qpid.msg_sequence"));
+
+ topic.route(dmsg6, "abc", 0);
+ BOOST_CHECK_EQUAL(1, msg6->getApplicationHeaders()->getAsInt64("qpid.msg_sequence"));
+ direct.encode(buffer);
+ }
+ {
+
+ ExchangeRegistry exchanges;
+ buffer.reset();
+ DirectExchange::shared_ptr exch_dec = Exchange::decode(exchanges, buffer);
+
+ intrusive_ptr<Message> msg1 = cmessage("e", "A");
+ DeliverableMessage dmsg1(msg1);
+ exch_dec->route(dmsg1, "abc", 0);
+
+ BOOST_CHECK_EQUAL(4, msg1->getApplicationHeaders()->getAsInt64("qpid.msg_sequence"));
+
+ }
+ delete [] buff;
+}
+
+QPID_AUTO_TEST_CASE(testIVEOption)
+{
+ FieldTable args;
+ args.setInt("qpid.ive",1);
+ DirectExchange direct("direct1", false, args);
+ FanOutExchange fanout("fanout1", false, args);
+ HeadersExchange header("headers1", false, args);
+ TopicExchange topic ("topic1", false, args);
+
+ intrusive_ptr<Message> msg1 = cmessage("direct1", "abc");
+ msg1->getProperties<MessageProperties>()->getApplicationHeaders().setString("a", "abc");
+ DeliverableMessage dmsg1(msg1);
+
+ FieldTable args2;
+ args2.setString("x-match", "any");
+ args2.setString("a", "abc");
+
+ direct.route(dmsg1, "abc", 0);
+ fanout.route(dmsg1, "abc", 0);
+ header.route(dmsg1, "abc", &args2);
+ topic.route(dmsg1, "abc", 0);
+ Queue::shared_ptr queue(new Queue("queue", true));
+ Queue::shared_ptr queue1(new Queue("queue1", true));
+ Queue::shared_ptr queue2(new Queue("queue2", true));
+ Queue::shared_ptr queue3(new Queue("queue3", true));
+
+ BOOST_CHECK(HeadersExchange::match(args2, msg1->getProperties<MessageProperties>()->getApplicationHeaders()));
+
+ BOOST_CHECK(direct.bind(queue, "abc", 0));
+ BOOST_CHECK(fanout.bind(queue1, "abc", 0));
+ BOOST_CHECK(header.bind(queue2, "", &args2));
+ BOOST_CHECK(topic.bind(queue3, "abc", 0));
+
+ BOOST_CHECK_EQUAL(1u,queue->getMessageCount());
+ BOOST_CHECK_EQUAL(1u,queue1->getMessageCount());
+ BOOST_CHECK_EQUAL(1u,queue2->getMessageCount());
+ BOOST_CHECK_EQUAL(1u,queue3->getMessageCount());
+
+}
+
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/FieldTable.cpp b/RC9/qpid/cpp/src/tests/FieldTable.cpp
new file mode 100644
index 0000000000..6b364723cf
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/FieldTable.cpp
@@ -0,0 +1,178 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <iostream>
+#include "qpid/framing/Array.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/FieldValue.h"
+#include <alloca.h>
+
+#include "unit_test.h"
+
+using namespace qpid::framing;
+
+QPID_AUTO_TEST_SUITE(FieldTableTestSuite)
+
+QPID_AUTO_TEST_CASE(testMe)
+{
+ FieldTable ft;
+ ft.setString("A", "BCDE");
+ BOOST_CHECK(string("BCDE") == ft.getAsString("A"));
+
+ char buff[100];
+ Buffer wbuffer(buff, 100);
+ wbuffer.put(ft);
+
+ Buffer rbuffer(buff, 100);
+ FieldTable ft2;
+ rbuffer.get(ft2);
+ BOOST_CHECK(string("BCDE") == ft2.getAsString("A"));
+
+}
+
+QPID_AUTO_TEST_CASE(testAssignment)
+{
+ FieldTable a;
+ FieldTable b;
+
+ a.setString("A", "BBBB");
+ a.setInt("B", 1234);
+ b = a;
+ a.setString("A", "CCCC");
+
+ BOOST_CHECK(string("CCCC") == a.getAsString("A"));
+ BOOST_CHECK(string("BBBB") == b.getAsString("A"));
+ BOOST_CHECK_EQUAL(1234, a.getAsInt("B"));
+ BOOST_CHECK_EQUAL(1234, b.getAsInt("B"));
+ BOOST_CHECK(IntegerValue(1234) == *a.get("B"));
+ BOOST_CHECK(IntegerValue(1234) == *b.get("B"));
+
+ FieldTable d;
+ {
+ FieldTable c;
+ c = a;
+
+ char* buff = static_cast<char*>(::alloca(c.encodedSize()));
+ Buffer wbuffer(buff, c.encodedSize());
+ wbuffer.put(c);
+
+ Buffer rbuffer(buff, c.encodedSize());
+ rbuffer.get(d);
+ BOOST_CHECK_EQUAL(c, d);
+ BOOST_CHECK(string("CCCC") == c.getAsString("A"));
+ BOOST_CHECK(IntegerValue(1234) == *c.get("B"));
+ }
+ BOOST_CHECK(string("CCCC") == d.getAsString("A"));
+ BOOST_CHECK(IntegerValue(1234) == *d.get("B"));
+}
+
+
+QPID_AUTO_TEST_CASE(testNestedValues)
+{
+ char buff[100];
+ {
+ FieldTable a;
+ FieldTable b;
+ std::vector<std::string> items;
+ items.push_back("one");
+ items.push_back("two");
+ Array c(items);
+
+ a.setString("id", "A");
+ b.setString("id", "B");
+ a.setTable("B", b);
+ a.setArray("C", c);
+
+
+ Buffer wbuffer(buff, 100);
+ wbuffer.put(a);
+ }
+ {
+ Buffer rbuffer(buff, 100);
+ FieldTable a;
+ FieldTable b;
+ Array c;
+ rbuffer.get(a);
+ BOOST_CHECK(string("A") == a.getAsString("id"));
+ a.getTable("B", b);
+ BOOST_CHECK(string("B") == b.getAsString("id"));
+ a.getArray("C", c);
+ std::vector<std::string> items;
+ c.collect(items);
+ BOOST_CHECK((uint) 2 == items.size());
+ BOOST_CHECK(string("one") == items[0]);
+ BOOST_CHECK(string("two") == items[1]);
+ }
+}
+
+QPID_AUTO_TEST_CASE(testFloatAndDouble)
+{
+ char buff[100];
+ float f = 5.672;
+ double d = 56.720001;
+ {
+ FieldTable a;
+ a.setString("string", "abc");
+ a.setInt("int", 5672);
+ a.setFloat("float", f);
+ a.setDouble("double", d);
+
+ Buffer wbuffer(buff, 100);
+ wbuffer.put(a);
+ }
+ {
+ Buffer rbuffer(buff, 100);
+ FieldTable a;
+ rbuffer.get(a);
+ BOOST_CHECK(string("abc") == a.getAsString("string"));
+ BOOST_CHECK(5672 == a.getAsInt("int"));
+ float f2;
+ BOOST_CHECK(!a.getFloat("string", f2));
+ BOOST_CHECK(!a.getFloat("int", f2));
+ BOOST_CHECK(a.getFloat("float", f2));
+ BOOST_CHECK(f2 == f);
+
+ double d2;
+ BOOST_CHECK(!a.getDouble("string", d2));
+ BOOST_CHECK(!a.getDouble("int", d2));
+ BOOST_CHECK(a.getDouble("double", d2));
+ BOOST_CHECK(d2 == d);
+ }
+}
+
+QPID_AUTO_TEST_CASE(test64GetAndSetConverts)
+{
+ FieldTable args;
+ args.setInt64("a",100);
+ args.setInt64("b",-(int64_t) ((int64_t) 1<<34));
+
+ args.setUInt64("c",1u);
+ args.setUInt64("d",(uint64_t) ((uint64_t) 1<<34));
+ BOOST_CHECK_EQUAL(1u, args.getAsUInt64("c"));
+ BOOST_CHECK_EQUAL(100u, args.getAsUInt64("a"));
+ BOOST_CHECK_EQUAL(1, args.getAsInt64("c"));
+ BOOST_CHECK_EQUAL(100, args.getAsInt64("a"));
+ BOOST_CHECK_EQUAL(-(int64_t) ((int64_t) 1<<34), args.getAsInt64("b"));
+ BOOST_CHECK_EQUAL((uint64_t) ((uint64_t) 1<<34), args.getAsUInt64("d"));
+ BOOST_CHECK_EQUAL((int64_t) ((int64_t) 1<<34), args.getAsInt64("d"));
+
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/FieldValue.cpp b/RC9/qpid/cpp/src/tests/FieldValue.cpp
new file mode 100644
index 0000000000..448f068107
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/FieldValue.cpp
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include "qpid/framing/FieldValue.h"
+
+#include "unit_test.h"
+
+QPID_AUTO_TEST_SUITE(FieldValueTestSuite)
+
+using namespace qpid::framing;
+
+Str16Value s("abc");
+IntegerValue i(42);
+//DecimalValue d(1234,2);
+//FieldTableValue ft;
+//EmptyValue e;
+
+QPID_AUTO_TEST_CASE(testStr16ValueEquals)
+{
+
+ BOOST_CHECK(Str16Value("abc") == s);
+ BOOST_CHECK(Str16Value("foo") != s);
+ BOOST_CHECK(s != i);
+ BOOST_CHECK(s.convertsTo<std::string>() == true);
+ BOOST_CHECK(s.convertsTo<int>() == false);
+ BOOST_CHECK(s.get<std::string>() == "abc");
+ BOOST_CHECK_THROW(s.get<int>(), InvalidConversionException);
+// BOOST_CHECK(s != ft);
+
+}
+
+QPID_AUTO_TEST_CASE(testIntegerValueEquals)
+{
+ BOOST_CHECK(IntegerValue(42) == i);
+ BOOST_CHECK(IntegerValue(5) != i);
+ BOOST_CHECK(i != s);
+ BOOST_CHECK(i.convertsTo<std::string>() == false);
+ BOOST_CHECK(i.convertsTo<int>() == true);
+ BOOST_CHECK_THROW(i.get<std::string>(), InvalidConversionException);
+ BOOST_CHECK(i.get<int>() == 42);
+// BOOST_CHECK(i != ft);
+}
+
+#if 0
+QPID_AUTO_TEST_CASE(testDecimalValueEquals)
+{
+ BOOST_CHECK(DecimalValue(1234, 2) == d);
+ BOOST_CHECK(DecimalValue(12345, 2) != d);
+ BOOST_CHECK(DecimalValue(1234, 3) != d);
+ BOOST_CHECK(d != s);
+}
+
+QPID_AUTO_TEST_CASE(testFieldTableValueEquals)
+{
+ ft.getValue().setString("foo", "FOO");
+ ft.getValue().setInt("magic", 7);
+
+ BOOST_CHECK_EQUAL(std::string("FOO"),
+ ft.getValue().getString("foo"));
+ BOOST_CHECK_EQUAL(7, ft.getValue().getInt("magic"));
+
+ FieldTableValue f2;
+ BOOST_CHECK(ft != f2);
+ f2.getValue().setString("foo", "FOO");
+ BOOST_CHECK(ft != f2);
+ f2.getValue().setInt("magic", 7);
+ BOOST_CHECK_EQUAL(ft,f2);
+ BOOST_CHECK(ft == f2);
+ f2.getValue().setString("foo", "BAR");
+ BOOST_CHECK(ft != f2);
+ BOOST_CHECK(ft != i);
+}
+#endif
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/ForkedBroker.h b/RC9/qpid/cpp/src/tests/ForkedBroker.h
new file mode 100644
index 0000000000..bf9e9265c4
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/ForkedBroker.h
@@ -0,0 +1,122 @@
+#ifndef TESTS_FORKEDBROKER_H
+
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/Exception.h"
+#include "qpid/log/Statement.h"
+#include "qpid/broker/Broker.h"
+#include <boost/lexical_cast.hpp>
+#include <string>
+#include <stdio.h>
+#include <sys/wait.h>
+
+/**
+ * Class to fork a broker child process.
+ *
+ * For most tests a BrokerFixture may be more convenient as it starts
+ * a broker in the same process which allows you to easily debug into
+ * the broker.
+ *
+ * This useful for tests that need to start multiple brokers where
+ * those brokers can't coexist in the same process (e.g. for cluster
+ * tests where CPG doesn't allow multiple group members in a single
+ * process.)
+ *
+ */
+class ForkedBroker {
+ public:
+ ForkedBroker(std::vector<const char*> argv) { init(argv); }
+
+ ForkedBroker(int argc, const char* const argv[]) {
+ std::vector<const char*> args(argv, argv+argc);
+ init(args);
+ }
+
+ ~ForkedBroker() {
+ try { kill(); } catch(const std::exception& e) {
+ QPID_LOG(error, QPID_MSG("Killing forked broker: " << e.what()));
+ }
+ }
+
+ void kill(int sig=SIGINT) {
+ if (pid == 0) return;
+ int savePid = pid;
+ pid = 0; // Reset pid here in case of an exception.
+ using qpid::ErrnoException;
+ if (::kill(savePid, sig) < 0)
+ throw ErrnoException("kill failed");
+ int status;
+ if (::waitpid(savePid, &status, 0) < 0)
+ throw ErrnoException("wait for forked process failed");
+ if (WEXITSTATUS(status) != 0)
+ throw qpid::Exception(QPID_MSG("Forked broker exited with: " << WEXITSTATUS(status)));
+ }
+
+ uint16_t getPort() { return port; }
+ pid_t getPID() { return pid; }
+
+ private:
+
+ template <class F> struct OnExit {
+ F fn;
+ OnExit(F f) : fn(f) {}
+ ~OnExit() { fn(); }
+ };
+
+ void init(const std::vector<const char*>& args) {
+ using qpid::ErrnoException;
+ port = 0;
+ int pipeFds[2];
+ if(::pipe(pipeFds) < 0) throw ErrnoException("Can't create pipe");
+ pid = ::fork();
+ if (pid < 0) throw ErrnoException("Fork failed");
+ if (pid) { // parent
+ ::close(pipeFds[1]);
+ FILE* f = ::fdopen(pipeFds[0], "r");
+ if (!f) throw ErrnoException("fopen failed");
+ if (::fscanf(f, "%d", &port) != 1) {
+ if (ferror(f)) throw ErrnoException("Error reading port number from child.");
+ else throw qpid::Exception("EOF reading port number from child.");
+ }
+ ::close(pipeFds[0]);
+ }
+ else { // child
+ ::close(pipeFds[0]);
+ int fd = ::dup2(pipeFds[1], 1); // pipe stdout to the parent.
+ if (fd < 0) throw ErrnoException("dup2 failed");
+ const char* prog = "../qpidd";
+ std::vector<const char*> args2(args);
+ args2.push_back("--port=0");
+ args2.push_back("--mgmt-enable=no"); // TODO aconway 2008-07-16: why does mgmt cause problems?
+ args2.push_back("--log-enable=error+"); // Keep quiet except for errors.
+ args2.push_back(0);
+ execv(prog, const_cast<char* const*>(&args2[0]));
+ throw ErrnoException("execv failed");
+ }
+ }
+
+ pid_t pid;
+ int port;
+};
+
+#endif /*!TESTS_FORKEDBROKER_H*/
diff --git a/RC9/qpid/cpp/src/tests/Frame.cpp b/RC9/qpid/cpp/src/tests/Frame.cpp
new file mode 100644
index 0000000000..11905911fa
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/Frame.cpp
@@ -0,0 +1,80 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/framing/Frame.h"
+
+#include <boost/lexical_cast.hpp>
+#include "unit_test.h"
+
+QPID_AUTO_TEST_SUITE(FrameTestSuite)
+
+using namespace std;
+using namespace qpid::framing;
+using namespace boost;
+
+QPID_AUTO_TEST_CASE(testContentBody) {
+ Frame f(42, AMQContentBody("foobar"));
+ AMQBody* body=f.getBody();
+ BOOST_CHECK(dynamic_cast<AMQContentBody*>(body));
+ Buffer b(f.encodedSize();
+ f.encode(b);
+ b.flip();
+ Frame g;
+ g.decode(b);
+ AMQContentBody* content=dynamic_cast<AMQContentBody*>(g.getBody());
+ BOOST_REQUIRE(content);
+ BOOST_CHECK_EQUAL(content->getData(), "foobar");
+}
+
+QPID_AUTO_TEST_CASE(testMethodBody) {
+ FieldTable args;
+ args.setString("foo", "bar");
+ Frame f(
+ 42, QueueDeclareBody(ProtocolVersion(), 1, "q", "altex",
+ true, false, true, false, true, args));
+ BOOST_CHECK_EQUAL(f.getChannel(), 42);
+ Buffer b(f.encodedSize();
+ f.encode(b);
+ b.flip();
+ Frame g;
+ g.decode(b);
+ BOOST_CHECK_EQUAL(f.getChannel(), g.getChannel());
+ QueueDeclareBody* declare=dynamic_cast<QueueDeclareBody*>(g.getBody());
+ BOOST_REQUIRE(declare);
+ BOOST_CHECK_EQUAL(declare->getAlternateExchange(), "altex");
+ BOOST_CHECK_EQUAL(lexical_cast<string>(*f.getBody()), lexical_cast<string>(*g.getBody()));
+}
+
+QPID_AUTO_TEST_CASE(testLoop) {
+ // Run in a loop so heap profiler can spot any allocations.
+ Buffer b(1024);
+ for (int i = 0; i < 100; ++i) {
+ Frame ctor(2, AccessRequestOkBody(ProtocolVersion(), 42));
+ Frame assign(3);
+ assign.body = AccessRequestOkBody(ProtocolVersion(), 42);
+ assign.encode(b);
+ b.flip();
+ Frame g;
+ g.decode(b);
+ BOOST_REQUIRE(dynamic_cast<AccessRequestOkBody*>(g.getBody())->getTicket() == 42);
+ }
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/FramingTest.cpp b/RC9/qpid/cpp/src/tests/FramingTest.cpp
new file mode 100644
index 0000000000..f82507c0a7
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/FramingTest.cpp
@@ -0,0 +1,151 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/client/Connection.h"
+#include "qpid/client/Connector.h"
+#include "qpid/framing/AMQP_HighestVersion.h"
+#include "qpid/framing/ProtocolVersion.h"
+#include "qpid/framing/all_method_bodies.h"
+#include "qpid/framing/amqp_framing.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "unit_test.h"
+
+#include <boost/bind.hpp>
+#include <boost/lexical_cast.hpp>
+#include <iostream>
+
+#include <memory>
+#include <sstream>
+#include <typeinfo>
+
+using namespace qpid;
+using namespace qpid::framing;
+using namespace std;
+
+template <class T>
+std::string tostring(const T& x)
+{
+ std::ostringstream out;
+ out << x;
+ return out.str();
+}
+
+QPID_AUTO_TEST_SUITE(FramingTestSuite)
+
+QPID_AUTO_TEST_CASE(testMessageTransferBody)
+{
+ char buffer[1024];
+ ProtocolVersion version(highestProtocolVersion);
+ Buffer wbuff(buffer, sizeof(buffer));
+ MessageTransferBody in(version, "my-exchange", 1, 1);
+ in.encode(wbuff);
+
+ Buffer rbuff(buffer, sizeof(buffer));
+ MessageTransferBody out(version);
+ out.decode(rbuff);
+ BOOST_CHECK_EQUAL(tostring(in), tostring(out));
+}
+
+QPID_AUTO_TEST_CASE(testConnectionSecureBody)
+{
+ char buffer[1024];
+ ProtocolVersion version(highestProtocolVersion);
+ Buffer wbuff(buffer, sizeof(buffer));
+ std::string s = "security credential";
+ ConnectionSecureBody in(version, s);
+ in.encode(wbuff);
+
+ Buffer rbuff(buffer, sizeof(buffer));
+ ConnectionSecureBody out(version);
+ out.decode(rbuff);
+ BOOST_CHECK_EQUAL(tostring(in), tostring(out));
+}
+
+QPID_AUTO_TEST_CASE(testConnectionRedirectBody)
+{
+ char buffer[1024];
+ ProtocolVersion version(highestProtocolVersion);
+ Buffer wbuff(buffer, sizeof(buffer));
+ std::string a = "hostA";
+ std::string b = "hostB";
+ Array hosts(0x95);
+ hosts.add(boost::shared_ptr<FieldValue>(new Str16Value(a)));
+ hosts.add(boost::shared_ptr<FieldValue>(new Str16Value(b)));
+
+ ConnectionRedirectBody in(version, a, hosts);
+ in.encode(wbuff);
+
+ Buffer rbuff(buffer, sizeof(buffer));
+ ConnectionRedirectBody out(version);
+ out.decode(rbuff);
+ BOOST_CHECK_EQUAL(tostring(in), tostring(out));
+}
+
+QPID_AUTO_TEST_CASE(testQueueDeclareBody)
+{
+ char buffer[1024];
+ ProtocolVersion version(highestProtocolVersion);
+ Buffer wbuff(buffer, sizeof(buffer));
+ QueueDeclareBody in(version, "name", "dlq", true, false, true, false, FieldTable());
+ in.encode(wbuff);
+
+ Buffer rbuff(buffer, sizeof(buffer));
+ QueueDeclareBody out(version);
+ out.decode(rbuff);
+ BOOST_CHECK_EQUAL(tostring(in), tostring(out));
+}
+
+QPID_AUTO_TEST_CASE(testConnectionRedirectBodyFrame)
+{
+ char buffer[1024];
+ ProtocolVersion version(highestProtocolVersion);
+ Buffer wbuff(buffer, sizeof(buffer));
+ std::string a = "hostA";
+ std::string b = "hostB";
+ Array hosts(0x95);
+ hosts.add(boost::shared_ptr<FieldValue>(new Str16Value(a)));
+ hosts.add(boost::shared_ptr<FieldValue>(new Str16Value(b)));
+
+ AMQFrame in(in_place<ConnectionRedirectBody>(version, a, hosts));
+ in.setChannel(999);
+ in.encode(wbuff);
+
+ Buffer rbuff(buffer, sizeof(buffer));
+ AMQFrame out;
+ out.decode(rbuff);
+ BOOST_CHECK_EQUAL(tostring(in), tostring(out));
+}
+
+QPID_AUTO_TEST_CASE(testMessageCancelBodyFrame)
+{
+ char buffer[1024];
+ ProtocolVersion version(highestProtocolVersion);
+ Buffer wbuff(buffer, sizeof(buffer));
+ AMQFrame in(in_place<MessageCancelBody>(version, "tag"));
+ in.setChannel(999);
+ in.encode(wbuff);
+
+ Buffer rbuff(buffer, sizeof(buffer));
+ AMQFrame out;
+ out.decode(rbuff);
+ BOOST_CHECK_EQUAL(tostring(in), tostring(out));
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/HeaderTest.cpp b/RC9/qpid/cpp/src/tests/HeaderTest.cpp
new file mode 100644
index 0000000000..33bf705e65
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/HeaderTest.cpp
@@ -0,0 +1,110 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <iostream>
+#include "qpid/framing/amqp_framing.h"
+#include "qpid/framing/FieldValue.h"
+#include "unit_test.h"
+
+using namespace qpid::framing;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(HeaderTestSuite)
+
+QPID_AUTO_TEST_CASE(testGenericProperties)
+{
+ AMQHeaderBody body;
+ body.get<MessageProperties>(true)->getApplicationHeaders().setString(
+ "A", "BCDE");
+ char buff[100];
+ Buffer wbuffer(buff, 100);
+ body.encode(wbuffer);
+
+ Buffer rbuffer(buff, 100);
+ AMQHeaderBody body2;
+ body2.decode(rbuffer, body.encodedSize());
+ MessageProperties* props =
+ body2.get<MessageProperties>(true);
+ BOOST_CHECK_EQUAL(
+ string("BCDE"),
+ props->getApplicationHeaders().get("A")->get<string>());
+}
+
+QPID_AUTO_TEST_CASE(testMessageProperties)
+{
+ AMQFrame out(in_place<AMQHeaderBody>());
+ MessageProperties* props1 =
+ out.castBody<AMQHeaderBody>()->get<MessageProperties>(true);
+
+ props1->setContentLength(42);
+ props1->setMessageId(Uuid(true));
+ props1->setCorrelationId("correlationId");
+ props1->setReplyTo(ReplyTo("ex","key"));
+ props1->setContentType("contentType");
+ props1->setContentEncoding("contentEncoding");
+ props1->setUserId("userId");
+ props1->setAppId("appId");
+
+ char buff[10000];
+ Buffer wbuffer(buff, 10000);
+ out.encode(wbuffer);
+
+ Buffer rbuffer(buff, 10000);
+ AMQFrame in;
+ in.decode(rbuffer);
+ MessageProperties* props2 =
+ in.castBody<AMQHeaderBody>()->get<MessageProperties>(true);
+
+ BOOST_CHECK_EQUAL(props1->getContentLength(), props2->getContentLength());
+ BOOST_CHECK_EQUAL(props1->getMessageId(), props2->getMessageId());
+ BOOST_CHECK_EQUAL(props1->getCorrelationId(), props2->getCorrelationId());
+ BOOST_CHECK_EQUAL(props1->getContentType(), props2->getContentType());
+ BOOST_CHECK_EQUAL(props1->getContentEncoding(), props2->getContentEncoding());
+ BOOST_CHECK_EQUAL(props1->getUserId(), props2->getUserId());
+ BOOST_CHECK_EQUAL(props1->getAppId(), props2->getAppId());
+
+}
+
+QPID_AUTO_TEST_CASE(testDeliveryProperies)
+{
+ AMQFrame out(in_place<AMQHeaderBody>());
+ DeliveryProperties* props1 =
+ out.castBody<AMQHeaderBody>()->get<DeliveryProperties>(true);
+
+ props1->setDiscardUnroutable(true);
+ props1->setExchange("foo");
+
+ char buff[10000];
+ Buffer wbuffer(buff, 10000);
+ out.encode(wbuffer);
+
+ Buffer rbuffer(buff, 10000);
+ AMQFrame in;
+ in.decode(rbuffer);
+ DeliveryProperties* props2 =
+ in.castBody<AMQHeaderBody>()->get<DeliveryProperties>(true);
+
+ BOOST_CHECK(props2->getDiscardUnroutable());
+ BOOST_CHECK_EQUAL(string("foo"), props2->getExchange());
+ BOOST_CHECK(!props2->hasTimestamp());
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
diff --git a/RC9/qpid/cpp/src/tests/HeadersExchangeTest.cpp b/RC9/qpid/cpp/src/tests/HeadersExchangeTest.cpp
new file mode 100644
index 0000000000..46933f955a
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/HeadersExchangeTest.cpp
@@ -0,0 +1,115 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/Exception.h"
+#include "qpid/broker/HeadersExchange.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/FieldValue.h"
+#include "unit_test.h"
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+QPID_AUTO_TEST_SUITE(HeadersExchangeTestSuite)
+
+QPID_AUTO_TEST_CASE(testMatchAll)
+{
+ FieldTable b, m, n;
+ b.setString("x-match", "all");
+ b.setString("foo", "FOO");
+ b.setInt("n", 42);
+ m.setString("foo", "FOO");
+ m.setInt("n", 42);
+ BOOST_CHECK(HeadersExchange::match(b, m));
+
+ // Ignore extras.
+ m.setString("extra", "x");
+ BOOST_CHECK(HeadersExchange::match(b, m));
+
+ // Fail mismatch, wrong value.
+ m.setString("foo", "NotFoo");
+ BOOST_CHECK(!HeadersExchange::match(b, m));
+
+ // Fail mismatch, missing value
+ n.setInt("n", 42);
+ n.setString("extra", "x");
+ BOOST_CHECK(!HeadersExchange::match(b, n));
+}
+
+QPID_AUTO_TEST_CASE(testMatchAny)
+{
+ FieldTable b, m, n;
+ b.setString("x-match", "any");
+ b.setString("foo", "FOO");
+ b.setInt("n", 42);
+ m.setString("foo", "FOO");
+ BOOST_CHECK(!HeadersExchange::match(b, n));
+ BOOST_CHECK(HeadersExchange::match(b, m));
+ m.setInt("n", 42);
+ BOOST_CHECK(HeadersExchange::match(b, m));
+}
+
+QPID_AUTO_TEST_CASE(testMatchEmptyValue)
+{
+ FieldTable b, m;
+ b.setString("x-match", "all");
+ b.set("foo", FieldTable::ValuePtr());
+ b.set("n", FieldTable::ValuePtr());
+ BOOST_CHECK(!HeadersExchange::match(b, m));
+ m.setString("foo", "blah");
+ m.setInt("n", 123);
+}
+
+QPID_AUTO_TEST_CASE(testMatchEmptyArgs)
+{
+ FieldTable b, m;
+ m.setString("foo", "FOO");
+
+ b.setString("x-match", "all");
+ BOOST_CHECK(HeadersExchange::match(b, m));
+ b.setString("x-match", "any");
+ BOOST_CHECK(!HeadersExchange::match(b, m));
+}
+
+
+QPID_AUTO_TEST_CASE(testMatchNoXMatch)
+{
+ FieldTable b, m;
+ b.setString("foo", "FOO");
+ m.setString("foo", "FOO");
+ BOOST_CHECK(!HeadersExchange::match(b, m));
+}
+
+QPID_AUTO_TEST_CASE(testBindNoXMatch)
+{
+ HeadersExchange exchange("test");
+ Queue::shared_ptr queue;
+ std::string key;
+ FieldTable args;
+ try {
+ //just checking this doesn't cause assertion etc
+ exchange.bind(queue, key, &args);
+ } catch(qpid::Exception&) {
+ //expected
+ }
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/IncompleteMessageList.cpp b/RC9/qpid/cpp/src/tests/IncompleteMessageList.cpp
new file mode 100644
index 0000000000..925cdbf43e
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/IncompleteMessageList.cpp
@@ -0,0 +1,128 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <iostream>
+#include <sstream>
+#include "qpid/broker/Message.h"
+#include "qpid/broker/NullMessageStore.h"
+#include "qpid/broker/Queue.h"
+#include "qpid/broker/IncompleteMessageList.h"
+
+#include "unit_test.h"
+
+QPID_AUTO_TEST_SUITE(IncompleteMessageListTestSuite)
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+struct Checker
+{
+ std::list<SequenceNumber> ids;
+
+ Checker() { }
+
+ Checker(uint start, uint end) {
+ for (uint i = start; i <= end; i++) {
+ ids.push_back(i);
+ }
+ }
+
+ Checker& expect(const SequenceNumber& id) {
+ ids.push_back(id);
+ return *this;
+ }
+
+ void operator()(boost::intrusive_ptr<Message> msg) {
+ BOOST_CHECK(!ids.empty());
+ BOOST_CHECK_EQUAL(msg->getCommandId(), ids.front());
+ ids.pop_front();
+ }
+};
+
+QPID_AUTO_TEST_CASE(testProcessSimple)
+{
+ IncompleteMessageList list;
+ SequenceNumber counter(1);
+ //fill up list with messages
+ for (int i = 0; i < 5; i++) {
+ boost::intrusive_ptr<Message> msg(new Message(counter++));
+ list.add(msg);
+ }
+ //process and ensure they are all passed to completion listener
+ list.process(Checker(1, 5), false);
+ //process again and ensure none are resent to listener
+ list.process(Checker(), false);
+}
+
+QPID_AUTO_TEST_CASE(testProcessWithIncomplete)
+{
+ IncompleteMessageList list;
+ SequenceNumber counter(1);
+ boost::intrusive_ptr<Message> middle;
+ //fill up list with messages
+ for (int i = 0; i < 5; i++) {
+ boost::intrusive_ptr<Message> msg(new Message(counter++));
+ list.add(msg);
+ if (i == 2) {
+ //mark a message in the middle as incomplete
+ msg->enqueueAsync();
+ middle = msg;
+ }
+ }
+ //process and ensure only message upto incomplete message are passed to listener
+ list.process(Checker(1, 2), false);
+ //mark message complete and re-process to get remaining messages sent to listener
+ middle->enqueueComplete();
+ list.process(Checker(3, 5), false);
+}
+
+
+struct MockStore : public NullMessageStore
+{
+ Queue::shared_ptr queue;
+ boost::intrusive_ptr<Message> msg;
+
+ void flush(const qpid::broker::PersistableQueue& q) {
+ BOOST_CHECK_EQUAL(queue.get(), &q);
+ msg->enqueueComplete();
+ }
+};
+
+QPID_AUTO_TEST_CASE(testSyncProcessWithIncomplete)
+{
+ IncompleteMessageList list;
+ SequenceNumber counter(1);
+ MockStore store;
+ store.queue = Queue::shared_ptr(new Queue("mock-queue"));
+ //fill up list with messages
+ for (int i = 0; i < 5; i++) {
+ boost::intrusive_ptr<Message> msg(new Message(counter++));
+ list.add(msg);
+ if (i == 2) {
+ //mark a message in the middle as incomplete
+ msg->enqueueAsync(store.queue, &store);
+ store.msg = msg;
+ }
+ }
+ //process with sync bit specified and ensure that all messages are passed to listener
+ list.process(Checker(1, 5), true);
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/InlineAllocator.cpp b/RC9/qpid/cpp/src/tests/InlineAllocator.cpp
new file mode 100644
index 0000000000..fe6eaefaf4
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/InlineAllocator.cpp
@@ -0,0 +1,63 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/InlineAllocator.h"
+#include "unit_test.h"
+
+QPID_AUTO_TEST_SUITE(InlineAllocatorTestSuite)
+
+using namespace qpid;
+using namespace std;
+
+QPID_AUTO_TEST_CASE(testAllocate) {
+ InlineAllocator<std::allocator<char>, 2> alloc;
+
+ char* p = alloc.allocate(1);
+ BOOST_CHECK(p == (char*)&alloc);
+ alloc.deallocate(p,1);
+
+ p = alloc.allocate(2);
+ BOOST_CHECK(p == (char*)&alloc);
+ alloc.deallocate(p,2);
+
+ p = alloc.allocate(3);
+ BOOST_CHECK(p != (char*)&alloc);
+ alloc.deallocate(p,3);
+}
+
+QPID_AUTO_TEST_CASE(testAllocateFull) {
+ InlineAllocator<std::allocator<char>, 1> alloc;
+
+ char* p = alloc.allocate(1);
+ BOOST_CHECK(p == (char*)&alloc);
+
+ char* q = alloc.allocate(1);
+ BOOST_CHECK(q != (char*)&alloc);
+
+ alloc.deallocate(p,1);
+ p = alloc.allocate(1);
+ BOOST_CHECK(p == (char*)&alloc);
+
+ alloc.deallocate(p,1);
+ alloc.deallocate(q,1);
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/InlineVector.cpp b/RC9/qpid/cpp/src/tests/InlineVector.cpp
new file mode 100644
index 0000000000..bcd36e47b4
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/InlineVector.cpp
@@ -0,0 +1,119 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/InlineVector.h"
+#include "unit_test.h"
+
+QPID_AUTO_TEST_SUITE(InlineVectorTestSuite)
+
+using namespace qpid;
+using namespace std;
+
+typedef InlineVector<int, 3> Vec;
+
+bool isInline(const Vec& v) {
+ return (const char*)&v <= (const char*)(&v[0]) &&
+ (const char*)(&v[0]) < (const char*)&v+sizeof(v);
+}
+
+QPID_AUTO_TEST_CASE(testCtor) {
+ {
+ Vec v;
+ BOOST_CHECK(isInline(v));
+ BOOST_CHECK(v.empty());
+ }
+ {
+ Vec v(3, 42);
+ BOOST_CHECK(isInline(v));
+ BOOST_CHECK_EQUAL(3u, v.size());
+ BOOST_CHECK_EQUAL(v[0], 42);
+ BOOST_CHECK_EQUAL(v[2], 42);
+
+ Vec u(v);
+ BOOST_CHECK(isInline(u));
+ BOOST_CHECK_EQUAL(3u, u.size());
+ BOOST_CHECK_EQUAL(u[0], 42);
+ BOOST_CHECK_EQUAL(u[2], 42);
+ }
+
+ {
+ Vec v(4, 42);
+
+ BOOST_CHECK_EQUAL(v.size(), 4u);
+ BOOST_CHECK(!isInline(v));
+ Vec u(v);
+ BOOST_CHECK_EQUAL(u.size(), 4u);
+ BOOST_CHECK(!isInline(u));
+ }
+}
+
+QPID_AUTO_TEST_CASE(testInsert) {
+ {
+ Vec v;
+ v.push_back(1);
+ BOOST_CHECK_EQUAL(v.size(), 1u);
+ BOOST_CHECK_EQUAL(v.back(), 1);
+ BOOST_CHECK(isInline(v));
+
+ v.insert(v.begin(), 2);
+ BOOST_CHECK_EQUAL(v.size(), 2u);
+ BOOST_CHECK_EQUAL(v.back(), 1);
+ BOOST_CHECK(isInline(v));
+
+ v.push_back(3);
+ BOOST_CHECK(isInline(v));
+
+ v.push_back(4);
+
+ BOOST_CHECK(!isInline(v));
+ }
+ {
+ Vec v(3,42);
+ v.insert(v.begin(), 9);
+ BOOST_CHECK_EQUAL(v.size(), 4u);
+ BOOST_CHECK(!isInline(v));
+ }
+ {
+ Vec v(3,42);
+ v.insert(v.begin()+1, 9);
+ BOOST_CHECK(!isInline(v));
+ BOOST_CHECK_EQUAL(v.size(), 4u);
+ }
+}
+
+QPID_AUTO_TEST_CASE(testAssign) {
+ Vec v(3,42);
+ Vec u;
+ u = v;
+ BOOST_CHECK(isInline(u));
+ u.push_back(4);
+ BOOST_CHECK(!isInline(u));
+ v = u;
+ BOOST_CHECK(!isInline(v));
+}
+
+QPID_AUTO_TEST_CASE(testResize) {
+ Vec v;
+ v.resize(5);
+ BOOST_CHECK(!isInline(v));
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/Makefile.am b/RC9/qpid/cpp/src/tests/Makefile.am
new file mode 100644
index 0000000000..3a608b2bae
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/Makefile.am
@@ -0,0 +1,245 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+AM_CXXFLAGS = $(WARNING_CFLAGS) -DBOOST_TEST_DYN_LINK
+INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../gen -I$(top_builddir)/src/gen
+
+abs_builddir=@abs_builddir@
+extra_libs =
+lib_client = $(abs_builddir)/../libqpidclient.la
+lib_common = $(abs_builddir)/../libqpidcommon.la
+lib_broker = $(abs_builddir)/../libqpidbroker.la
+lib_console = $(abs_builddir)/../libqmfconsole.la
+# lib_amqp_0_10 = $(abs_builddir)/../libqpidamqp_0_10.la
+
+#
+# Initialize variables that are incremented with +=
+#
+check_PROGRAMS=
+check_LTLIBRARIES=
+TESTS=
+EXTRA_DIST=
+CLEANFILES=
+
+#
+# Unit test program
+#
+# Unit tests are built as a single program to reduce valgrind overhead
+# when running the tests. If you want to build a subset of the tests do
+# rm -f unit_test; make unit_test unit_test_OBJECTS="unit_test.o SelectedTest.o"
+#
+
+TESTS+=unit_test
+check_PROGRAMS+=unit_test
+unit_test_LDADD=-lboost_unit_test_framework -lboost_regex \
+ $(lib_client) $(lib_broker) $(lib_console)
+
+unit_test_SOURCES= unit_test.cpp unit_test.h \
+ BrokerFixture.h SocketProxy.h \
+ exception_test.cpp \
+ RefCounted.cpp \
+ SessionState.cpp Blob.cpp logging.cpp \
+ AsyncCompletion.cpp \
+ Url.cpp Uuid.cpp \
+ Shlib.cpp FieldValue.cpp FieldTable.cpp Array.cpp \
+ QueueOptionsTest.cpp \
+ InlineAllocator.cpp \
+ InlineVector.cpp \
+ ClientSessionTest.cpp \
+ SequenceSet.cpp \
+ StringUtils.cpp \
+ IncompleteMessageList.cpp \
+ RangeSet.cpp \
+ AtomicValue.cpp \
+ QueueTest.cpp \
+ AccumulatedAckTest.cpp \
+ DtxWorkRecordTest.cpp \
+ DeliveryRecordTest.cpp \
+ ExchangeTest.cpp \
+ HeadersExchangeTest.cpp \
+ MessageTest.cpp \
+ QueueRegistryTest.cpp \
+ QueuePolicyTest.cpp \
+ FramingTest.cpp \
+ HeaderTest.cpp \
+ SequenceNumberTest.cpp \
+ TimerTest.cpp \
+ TopicExchangeTest.cpp \
+ TxBufferTest.cpp \
+ TxPublishTest.cpp \
+ MessageBuilderTest.cpp \
+ ConnectionOptions.h \
+ ForkedBroker.h \
+ ManagementTest.cpp \
+ MessageReplayTracker.cpp \
+ ConsoleTest.cpp
+
+if HAVE_XML
+unit_test_SOURCES+= XmlClientSessionTest.cpp
+endif
+
+
+# Disabled till we move to amqp_0_10 codec.
+# amqp_0_10/serialize.cpp allSegmentTypes.h \
+# amqp_0_10/ProxyTemplate.cpp \
+# amqp_0_10/apply.cpp \
+# amqp_0_10/Map.cpp \
+# amqp_0_10/handlers.cpp
+
+
+check_LTLIBRARIES += libshlibtest.la
+libshlibtest_la_LDFLAGS = -module -rpath $(abs_builddir)
+libshlibtest_la_SOURCES = shlibtest.cpp
+
+include cluster.mk
+if SSL
+include ssl.mk
+endif
+
+#
+# Other test programs
+#
+check_PROGRAMS+=perftest
+perftest_SOURCES=perftest.cpp test_tools.h TestOptions.h ConnectionOptions.h
+perftest_LDADD=$(lib_client)
+
+check_PROGRAMS+=txtest
+txtest_SOURCES=txtest.cpp TestOptions.h ConnectionOptions.h
+txtest_LDADD=$(lib_client)
+
+check_PROGRAMS+=latencytest
+latencytest_SOURCES=latencytest.cpp TestOptions.h ConnectionOptions.h
+latencytest_LDADD=$(lib_client)
+
+check_PROGRAMS+=echotest
+echotest_SOURCES=echotest.cpp TestOptions.h ConnectionOptions.h
+echotest_LDADD=$(lib_client)
+
+check_PROGRAMS+=client_test
+client_test_SOURCES=client_test.cpp TestOptions.h ConnectionOptions.h
+client_test_LDADD=$(lib_client)
+
+check_PROGRAMS+=topic_listener
+topic_listener_SOURCES=topic_listener.cpp TestOptions.h ConnectionOptions.h
+topic_listener_LDADD=$(lib_client)
+
+check_PROGRAMS+=topic_publisher
+topic_publisher_SOURCES=topic_publisher.cpp TestOptions.h ConnectionOptions.h
+topic_publisher_LDADD=$(lib_client)
+
+check_PROGRAMS+=publish
+publish_SOURCES=publish.cpp TestOptions.h ConnectionOptions.h
+publish_LDADD=$(lib_client)
+
+check_PROGRAMS+=consume
+consume_SOURCES=consume.cpp TestOptions.h ConnectionOptions.h
+consume_LDADD=$(lib_client)
+
+check_PROGRAMS+=header_test
+header_test_SOURCES=header_test.cpp TestOptions.h ConnectionOptions.h
+header_test_LDADD=$(lib_client)
+
+check_PROGRAMS+=failover_soak
+failover_soak_SOURCES=failover_soak.cpp ForkedBroker.h
+failover_soak_LDADD=$(lib_client)
+
+check_PROGRAMS+=declare_queues
+declare_queues_SOURCES=declare_queues.cpp
+declare_queues_LDADD=$(lib_client)
+
+check_PROGRAMS+=replaying_sender
+replaying_sender_SOURCES=replaying_sender.cpp
+replaying_sender_LDADD=$(lib_client)
+
+check_PROGRAMS+=resuming_receiver
+resuming_receiver_SOURCES=resuming_receiver.cpp
+resuming_receiver_LDADD=$(lib_client)
+
+check_PROGRAMS+=txshift
+txshift_SOURCES=txshift.cpp TestOptions.h ConnectionOptions.h
+txshift_LDADD=$(lib_client)
+
+check_PROGRAMS+=txjob
+txjob_SOURCES=txjob.cpp TestOptions.h ConnectionOptions.h
+txjob_LDADD=$(lib_client)
+
+check_PROGRAMS+=receiver
+receiver_SOURCES=receiver.cpp TestOptions.h ConnectionOptions.h
+receiver_LDADD=$(lib_client)
+
+check_PROGRAMS+=sender
+sender_SOURCES=sender.cpp TestOptions.h ConnectionOptions.h
+sender_LDADD=$(lib_client)
+
+
+TESTS_ENVIRONMENT = VALGRIND=$(VALGRIND) srcdir=$(srcdir) QPID_DATA_DIR= BOOST_TEST_SHOW_PROGRESS=yes $(srcdir)/run_test
+
+system_tests = client_test quick_perftest quick_topictest run_header_test quick_txtest
+TESTS += start_broker $(system_tests) python_tests stop_broker run_federation_tests run_acl_tests
+
+EXTRA_DIST += \
+ run_test vg_check \
+ run-unit-tests start_broker python_tests stop_broker \
+ quick_topictest \
+ quick_perftest \
+ quick_txtest \
+ topictest \
+ run_header_test \
+ header_test.py \
+ ssl_test \
+ config.null \
+ ais_check \
+ run_federation_tests \
+ run_acl_tests \
+ .valgrind.supp \
+ MessageUtils.h \
+ TestMessageStore.h \
+ TxMocks.h \
+ start_cluster stop_cluster restart_cluster
+
+check_LTLIBRARIES += libdlclose_noop.la
+libdlclose_noop_la_LDFLAGS = -module -rpath $(abs_builddir)
+libdlclose_noop_la_SOURCES = dlclose_noop.c
+
+CLEANFILES+=valgrind.out *.log *.vglog* dummy_test $(unit_wrappers)
+
+# FIXME aconway 2008-05-23: Disabled interop_runner because it uses
+# the obsolete Channel class. Convert to Session and re-enable.
+#
+# check_PROGRAMS += interop_runner
+
+# interop_runner_SOURCES = \
+# interop_runner.cpp \
+# SimpleTestCaseBase.cpp \
+# BasicP2PTest.cpp \
+# BasicPubSubTest.cpp \
+# SimpleTestCaseBase.h \
+# BasicP2PTest.h \
+# BasicPubSubTest.h \
+# TestCase.h \
+# TestOptions.h ConnectionOptions.h
+# interop_runner_LDADD = $(lib_client) $(lib_common) $(extra_libs)
+
+
+# Longer running stability tests, not run by default check: target.
+# Not run under valgrind, too slow
+LONG_TESTS=fanout_perftest shared_perftest multiq_perftest topic_perftest run_failover_soak
+EXTRA_DIST+=$(LONG_TESTS) run_perftest
+check-long:
+ $(MAKE) check TESTS="start_broker $(LONG_TESTS) stop_broker" VALGRIND=
diff --git a/RC9/qpid/cpp/src/tests/ManagementTest.cpp b/RC9/qpid/cpp/src/tests/ManagementTest.cpp
new file mode 100644
index 0000000000..a3d29ec22c
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/ManagementTest.cpp
@@ -0,0 +1,85 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/management/ManagementObject.h"
+#include "qpid/framing/Buffer.h"
+#include "unit_test.h"
+
+QPID_AUTO_TEST_SUITE(ManagementTestSuite)
+
+using namespace qpid::framing;
+using namespace qpid::management;
+
+QPID_AUTO_TEST_CASE(testObjectIdSerializeStream) {
+ std::string text("0-10-4-2500-80000000000");
+ std::stringstream input(text);
+
+ ObjectId oid(input);
+
+ std::stringstream output;
+ output << oid;
+
+ BOOST_CHECK_EQUAL(text, output.str());
+}
+
+QPID_AUTO_TEST_CASE(testObjectIdSerializeString) {
+ std::string text("0-10-4-2500-80000000000");
+
+ ObjectId oid(text);
+
+ std::stringstream output;
+ output << oid;
+
+ BOOST_CHECK_EQUAL(text, output.str());
+}
+
+QPID_AUTO_TEST_CASE(testObjectIdEncode) {
+ char buffer[100];
+ Buffer msgBuf(buffer, 100);
+ msgBuf.putLongLong(0x1002000030000004LL);
+ msgBuf.putLongLong(0x0000000000000005LL);
+ msgBuf.reset();
+
+ ObjectId oid(msgBuf);
+
+ std::stringstream out1;
+ out1 << oid;
+
+ BOOST_CHECK_EQUAL(out1.str(), "1-2-3-4-5");
+}
+
+QPID_AUTO_TEST_CASE(testObjectIdAttach) {
+ AgentAttachment agent;
+ ObjectId oid(&agent, 10, 20, 50);
+
+ std::stringstream out1;
+ out1 << oid;
+ BOOST_CHECK_EQUAL(out1.str(), "10-20-0-0-50");
+
+ agent.setBanks(30, 40);
+ std::stringstream out2;
+ out2 << oid;
+ BOOST_CHECK_EQUAL(out2.str(), "10-20-30-40-50");
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+
diff --git a/RC9/qpid/cpp/src/tests/MessageBuilderTest.cpp b/RC9/qpid/cpp/src/tests/MessageBuilderTest.cpp
new file mode 100644
index 0000000000..313a91c053
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/MessageBuilderTest.cpp
@@ -0,0 +1,224 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/broker/Message.h"
+#include "qpid/broker/MessageBuilder.h"
+#include "qpid/broker/NullMessageStore.h"
+#include "qpid/framing/frame_functors.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/framing/TypeFilter.h"
+#include "unit_test.h"
+#include <list>
+
+using namespace boost;
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+class MockMessageStore : public NullMessageStore
+{
+ enum Op {STAGE=1, APPEND=2};
+
+ uint64_t id;
+ intrusive_ptr<PersistableMessage> expectedMsg;
+ string expectedData;
+ std::list<Op> ops;
+
+ void checkExpectation(Op actual)
+ {
+ BOOST_CHECK_EQUAL(ops.front(), actual);
+ ops.pop_front();
+ }
+
+ public:
+ MockMessageStore() : id(0), expectedMsg(0) {}
+
+ void expectStage(PersistableMessage& msg)
+ {
+ expectedMsg = &msg;
+ ops.push_back(STAGE);
+ }
+
+ void expectAppendContent(PersistableMessage& msg, const string& data)
+ {
+ expectedMsg = &msg;
+ expectedData = data;
+ ops.push_back(APPEND);
+ }
+
+ void stage(const intrusive_ptr<PersistableMessage>& msg)
+ {
+ checkExpectation(STAGE);
+ BOOST_CHECK_EQUAL(expectedMsg, msg);
+ msg->setPersistenceId(++id);
+ }
+
+ void appendContent(const intrusive_ptr<const PersistableMessage>& msg,
+ const string& data)
+ {
+ checkExpectation(APPEND);
+ BOOST_CHECK_EQUAL(static_pointer_cast<const PersistableMessage>(expectedMsg), msg);
+ BOOST_CHECK_EQUAL(expectedData, data);
+ }
+
+ bool expectationsMet()
+ {
+ return ops.empty();
+ }
+
+ //don't treat this store as a null impl
+ bool isNull() const
+ {
+ return false;
+ }
+
+};
+
+QPID_AUTO_TEST_SUITE(MessageBuilderTestSuite)
+
+QPID_AUTO_TEST_CASE(testHeaderOnly)
+{
+ MessageBuilder builder(0, 0);
+ builder.start(SequenceNumber());
+
+ std::string exchange("builder-exchange");
+ std::string key("builder-exchange");
+
+ AMQFrame method(in_place<MessageTransferBody>(
+ ProtocolVersion(), exchange, 0, 0));
+ AMQFrame header(in_place<AMQHeaderBody>());
+
+ header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(0);
+ header.castBody<AMQHeaderBody>()->get<DeliveryProperties>(true)->setRoutingKey(key);
+
+ builder.handle(method);
+ builder.handle(header);
+
+ BOOST_CHECK(builder.getMessage());
+ BOOST_CHECK_EQUAL(exchange, builder.getMessage()->getExchangeName());
+ BOOST_CHECK_EQUAL(key, builder.getMessage()->getRoutingKey());
+ BOOST_CHECK(builder.getMessage()->getFrames().isComplete());
+}
+
+QPID_AUTO_TEST_CASE(test1ContentFrame)
+{
+ MessageBuilder builder(0, 0);
+ builder.start(SequenceNumber());
+
+ std::string data("abcdefg");
+ std::string exchange("builder-exchange");
+ std::string key("builder-exchange");
+
+ AMQFrame method(in_place<MessageTransferBody>(ProtocolVersion(), exchange, 0, 0));
+ AMQFrame header(in_place<AMQHeaderBody>());
+ AMQFrame content(in_place<AMQContentBody>(data));
+ method.setEof(false);
+ header.setBof(false);
+ header.setEof(false);
+ content.setBof(false);
+
+ header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(data.size());
+ header.castBody<AMQHeaderBody>()->get<DeliveryProperties>(true)->setRoutingKey(key);
+
+ builder.handle(method);
+ BOOST_CHECK(builder.getMessage());
+ BOOST_CHECK(!builder.getMessage()->getFrames().isComplete());
+
+ builder.handle(header);
+ BOOST_CHECK(builder.getMessage());
+ BOOST_CHECK(!builder.getMessage()->getFrames().isComplete());
+
+ builder.handle(content);
+ BOOST_CHECK(builder.getMessage());
+ BOOST_CHECK(builder.getMessage()->getFrames().isComplete());
+}
+
+QPID_AUTO_TEST_CASE(test2ContentFrames)
+{
+ MessageBuilder builder(0, 0);
+ builder.start(SequenceNumber());
+
+ std::string data1("abcdefg");
+ std::string data2("hijklmn");
+ std::string exchange("builder-exchange");
+ std::string key("builder-exchange");
+
+ AMQFrame method(in_place<MessageTransferBody>(
+ ProtocolVersion(), exchange, 0, 0));
+ AMQFrame header(in_place<AMQHeaderBody>());
+ AMQFrame content1(in_place<AMQContentBody>(data1));
+ AMQFrame content2(in_place<AMQContentBody>(data2));
+ method.setEof(false);
+ header.setBof(false);
+ header.setEof(false);
+ content1.setBof(false);
+ content1.setEof(false);
+ content2.setBof(false);
+
+ header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(data1.size() + data2.size());
+ header.castBody<AMQHeaderBody>()->get<DeliveryProperties>(true)->setRoutingKey(key);
+
+ builder.handle(method);
+ builder.handle(header);
+ builder.handle(content1);
+ BOOST_CHECK(builder.getMessage());
+ BOOST_CHECK(!builder.getMessage()->getFrames().isComplete());
+
+ builder.handle(content2);
+ BOOST_CHECK(builder.getMessage());
+ BOOST_CHECK(builder.getMessage()->getFrames().isComplete());
+}
+
+QPID_AUTO_TEST_CASE(testStaging)
+{
+ MockMessageStore store;
+ MessageBuilder builder(&store, 5);
+ builder.start(SequenceNumber());
+
+ std::string data1("abcdefg");
+ std::string data2("hijklmn");
+ std::string exchange("builder-exchange");
+ std::string key("builder-exchange");
+
+ AMQFrame method(in_place<MessageTransferBody>(
+ ProtocolVersion(), exchange, 0, 0));
+ AMQFrame header(in_place<AMQHeaderBody>());
+ AMQFrame content1(in_place<AMQContentBody>(data1));
+ AMQFrame content2(in_place<AMQContentBody>(data2));
+
+ header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(data1.size() + data2.size());
+ header.castBody<AMQHeaderBody>()->get<DeliveryProperties>(true)->setRoutingKey(key);
+
+ builder.handle(method);
+ builder.handle(header);
+
+ store.expectStage(*builder.getMessage());
+ builder.handle(content1);
+ BOOST_CHECK(store.expectationsMet());
+ BOOST_CHECK_EQUAL((uint64_t) 1, builder.getMessage()->getPersistenceId());
+
+ store.expectAppendContent(*builder.getMessage(), data2);
+ builder.handle(content2);
+ BOOST_CHECK(store.expectationsMet());
+ //were the content frames dropped?
+ BOOST_CHECK(!builder.getMessage()->isContentLoaded());
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/MessageReplayTracker.cpp b/RC9/qpid/cpp/src/tests/MessageReplayTracker.cpp
new file mode 100644
index 0000000000..a5121cdeb7
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/MessageReplayTracker.cpp
@@ -0,0 +1,99 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "unit_test.h"
+#include "BrokerFixture.h"
+#include "qpid/client/MessageReplayTracker.h"
+#include "qpid/sys/Time.h"
+
+QPID_AUTO_TEST_SUITE(MessageReplayTrackerTests)
+
+using namespace qpid::client;
+using namespace qpid::sys;
+using std::string;
+
+class ReplayBufferChecker
+{
+ public:
+
+ ReplayBufferChecker(uint from, uint to) : end(to), i(from) {}
+
+ void operator()(const Message& m)
+ {
+ if (i > end) BOOST_FAIL("Extra message found: " + m.getData());
+ BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i++)).str(), m.getData());
+ }
+ private:
+ const uint end;
+ uint i;
+
+};
+
+QPID_AUTO_TEST_CASE(testReplay)
+{
+ ProxySessionFixture fix;
+ fix.session.queueDeclare(arg::queue="my-queue", arg::exclusive=true, arg::autoDelete=true);
+
+ MessageReplayTracker tracker(10);
+ tracker.init(fix.session);
+ for (uint i = 0; i < 5; i++) {
+ Message message((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
+ tracker.send(message);
+ }
+ ReplayBufferChecker checker(1, 10);
+ tracker.foreach(checker);
+
+ tracker.replay(fix.session);
+ for (uint j = 0; j < 2; j++) {//each message should have been sent twice
+ for (uint i = 0; i < 5; i++) {
+ Message m;
+ BOOST_CHECK(fix.subs.get(m, "my-queue", TIME_SEC));
+ BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i+1)).str(), m.getData());
+ }
+ }
+ Message m;
+ BOOST_CHECK(!fix.subs.get(m, "my-queue"));
+}
+
+QPID_AUTO_TEST_CASE(testCheckCompletion)
+{
+ ProxySessionFixture fix;
+ fix.session.queueDeclare(arg::queue="my-queue", arg::exclusive=true, arg::autoDelete=true);
+
+ MessageReplayTracker tracker(10);
+ tracker.init(fix.session);
+ for (uint i = 0; i < 5; i++) {
+ Message message((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
+ tracker.send(message);
+ }
+ fix.session.sync();//ensures all messages are complete
+ tracker.checkCompletion();
+ tracker.replay(fix.session);
+ Message received;
+ for (uint i = 0; i < 5; i++) {
+ BOOST_CHECK(fix.subs.get(received, "my-queue"));
+ BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i+1)).str(), received.getData());
+ }
+ BOOST_CHECK(!fix.subs.get(received, "my-queue"));
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+
diff --git a/RC9/qpid/cpp/src/tests/MessageTest.cpp b/RC9/qpid/cpp/src/tests/MessageTest.cpp
new file mode 100644
index 0000000000..f9292ee53e
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/MessageTest.cpp
@@ -0,0 +1,90 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/broker/Message.h"
+#include "qpid/framing/AMQP_HighestVersion.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/framing/FieldValue.h"
+#include "qpid/framing/Uuid.h"
+
+#include "unit_test.h"
+
+#include <iostream>
+#include <alloca.h>
+
+using namespace boost;
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+QPID_AUTO_TEST_SUITE(MessageTestSuite)
+
+QPID_AUTO_TEST_CASE(testEncodeDecode)
+{
+ string exchange = "MyExchange";
+ string routingKey = "MyRoutingKey";
+ Uuid messageId(true);
+ string data1("abcdefg");
+ string data2("hijklmn");
+
+ intrusive_ptr<Message> msg(new Message());
+
+ AMQFrame method(in_place<MessageTransferBody>(
+ ProtocolVersion(), exchange, 0, 0));
+ AMQFrame header(in_place<AMQHeaderBody>());
+ AMQFrame content1(in_place<AMQContentBody>(data1));
+ AMQFrame content2(in_place<AMQContentBody>(data2));
+
+ msg->getFrames().append(method);
+ msg->getFrames().append(header);
+ msg->getFrames().append(content1);
+ msg->getFrames().append(content2);
+
+ MessageProperties* mProps = msg->getFrames().getHeaders()->get<MessageProperties>(true);
+ mProps->setContentLength(data1.size() + data2.size());
+ mProps->setMessageId(messageId);
+ FieldTable applicationHeaders;
+ applicationHeaders.setString("abc", "xyz");
+ mProps->setApplicationHeaders(applicationHeaders);
+ DeliveryProperties* dProps = msg->getFrames().getHeaders()->get<DeliveryProperties>(true);
+ dProps->setRoutingKey(routingKey);
+ dProps->setDeliveryMode(PERSISTENT);
+ BOOST_CHECK(msg->isPersistent());
+
+ char* buff = static_cast<char*>(::alloca(msg->encodedSize()));
+ Buffer wbuffer(buff, msg->encodedSize());
+ msg->encode(wbuffer);
+
+ Buffer rbuffer(buff, msg->encodedSize());
+ msg = new Message();
+ msg->decodeHeader(rbuffer);
+ msg->decodeContent(rbuffer);
+ BOOST_CHECK_EQUAL(exchange, msg->getExchangeName());
+ BOOST_CHECK_EQUAL(routingKey, msg->getRoutingKey());
+ BOOST_CHECK_EQUAL((uint64_t) data1.size() + data2.size(), msg->contentSize());
+ BOOST_CHECK_EQUAL((uint64_t) data1.size() + data2.size(), msg->getProperties<MessageProperties>()->getContentLength());
+ BOOST_CHECK_EQUAL(messageId, msg->getProperties<MessageProperties>()->getMessageId());
+ BOOST_CHECK_EQUAL(string("xyz"), msg->getProperties<MessageProperties>()->getApplicationHeaders().getAsString("abc"));
+ BOOST_CHECK_EQUAL((uint8_t) PERSISTENT, msg->getProperties<DeliveryProperties>()->getDeliveryMode());
+ BOOST_CHECK(msg->isPersistent());
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
diff --git a/RC9/qpid/cpp/src/tests/MessageUtils.h b/RC9/qpid/cpp/src/tests/MessageUtils.h
new file mode 100644
index 0000000000..81508e534e
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/MessageUtils.h
@@ -0,0 +1,55 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/broker/Message.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/framing/Uuid.h"
+
+using namespace qpid;
+using namespace broker;
+using namespace framing;
+
+struct MessageUtils
+{
+ static boost::intrusive_ptr<Message> createMessage(const string& exchange="", const string& routingKey="",
+ const Uuid& messageId=Uuid(true), uint64_t contentSize = 0)
+ {
+ boost::intrusive_ptr<Message> msg(new Message());
+
+ AMQFrame method(in_place<MessageTransferBody>(ProtocolVersion(), exchange, 0, 0));
+ AMQFrame header(in_place<AMQHeaderBody>());
+
+ msg->getFrames().append(method);
+ msg->getFrames().append(header);
+ MessageProperties* props = msg->getFrames().getHeaders()->get<MessageProperties>(true);
+ props->setContentLength(contentSize);
+ props->setMessageId(messageId);
+ msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setRoutingKey(routingKey);
+ return msg;
+ }
+
+ static void addContent(boost::intrusive_ptr<Message> msg, const string& data)
+ {
+ AMQFrame content(in_place<AMQContentBody>(data));
+ msg->getFrames().append(content);
+ }
+};
diff --git a/RC9/qpid/cpp/src/tests/PollerTest.cpp b/RC9/qpid/cpp/src/tests/PollerTest.cpp
new file mode 100644
index 0000000000..fcb1d0dadf
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/PollerTest.cpp
@@ -0,0 +1,164 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/**
+ * Use socketpair to test the poller
+ */
+
+#include "qpid/sys/Poller.h"
+
+#include <string>
+#include <iostream>
+#include <memory>
+#include <exception>
+
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+using namespace std;
+using namespace qpid::sys;
+
+int writeALot(int fd, const string& s) {
+ int bytesWritten = 0;
+ do {
+ errno = 0;
+ int lastWrite = ::write(fd, s.c_str(), s.size());
+ if ( lastWrite >= 0) {
+ bytesWritten += lastWrite;
+ }
+ } while (errno != EAGAIN);
+ return bytesWritten;
+}
+
+int readALot(int fd) {
+ int bytesRead = 0;
+ char buf[1024];
+
+ do {
+ errno = 0;
+ int lastRead = ::read(fd, buf, sizeof(buf));
+ if ( lastRead >= 0) {
+ bytesRead += lastRead;
+ }
+ } while (errno != EAGAIN);
+ return bytesRead;
+}
+
+int main(int argc, char** argv)
+{
+ try
+ {
+ int sv[2];
+ int rc = ::socketpair(AF_LOCAL, SOCK_STREAM, 0, sv);
+ assert(rc >= 0);
+
+ // Set non-blocking
+ rc = ::fcntl(sv[0], F_SETFL, O_NONBLOCK);
+ assert(rc >= 0);
+
+ rc = ::fcntl(sv[1], F_SETFL, O_NONBLOCK);
+ assert(rc >= 0);
+
+ // Make up a large string
+ string testString = "This is only a test ... 1,2,3,4,5,6,7,8,9,10;";
+ for (int i = 0; i < 6; i++)
+ testString += testString;
+
+ // Read as much as we can from socket 0
+ int bytesRead = readALot(sv[0]);
+ assert(bytesRead == 0);
+ cout << "Read(0): " << bytesRead << " bytes\n";
+
+ // Write as much as we can to socket 0
+ int bytesWritten = writeALot(sv[0], testString);
+ cout << "Wrote(0): " << bytesWritten << " bytes\n";
+
+ // Read as much as we can from socket 1
+ bytesRead = readALot(sv[1]);
+ assert(bytesRead == bytesWritten);
+ cout << "Read(1): " << bytesRead << " bytes\n";
+
+ auto_ptr<Poller> poller(new Poller);
+
+ PollerHandle h0(sv[0]);
+ PollerHandle h1(sv[1]);
+
+ poller->addFd(h0, Poller::INOUT);
+
+ // Wait for 500ms - h0 should be writable
+ Poller::Event event = poller->wait();
+ assert(event.handle == &h0);
+ assert(event.dir == Poller::OUT);
+
+ // Write as much as we can to socket 0
+ bytesWritten = writeALot(sv[0], testString);
+ cout << "Wrote(0): " << bytesWritten << " bytes\n";
+
+ // Wait for 500ms - h0 no longer writable
+ poller->rearmFd(h0);
+ event = poller->wait(500000000);
+ assert(event.handle == 0);
+
+ // Test we can read it all now
+ poller->addFd(h1, Poller::INOUT);
+ event = poller->wait();
+ assert(event.handle == &h1);
+ assert(event.dir == Poller::INOUT);
+
+ bytesRead = readALot(sv[1]);
+ assert(bytesRead == bytesWritten);
+ cout << "Read(1): " << bytesRead << " bytes\n";
+
+ // At this point h1 should have been disabled from the poller
+ // (as it was just returned) and h0 can write again
+ event = poller->wait();
+ assert(event.handle == &h0);
+ assert(event.dir == Poller::OUT);
+
+ // Now both the handles should be disabled
+ event = poller->wait(500000000);
+ assert(event.handle == 0);
+
+ // Test shutdown
+ poller->shutdown();
+ event = poller->wait();
+ assert(event.handle == 0);
+ assert(event.dir == Poller::SHUTDOWN);
+
+ event = poller->wait();
+ assert(event.handle == 0);
+ assert(event.dir == Poller::SHUTDOWN);
+
+ poller->delFd(h1);
+ poller->delFd(h0);
+
+ return 0;
+ } catch (exception& e) {
+ cout << "Caught exception " << e.what() << "\n";
+ }
+}
+
+
diff --git a/RC9/qpid/cpp/src/tests/QueueOptionsTest.cpp b/RC9/qpid/cpp/src/tests/QueueOptionsTest.cpp
new file mode 100644
index 0000000000..bac369bfec
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/QueueOptionsTest.cpp
@@ -0,0 +1,98 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <iostream>
+#include "qpid/framing/Array.h"
+#include "qpid/client/QueueOptions.h"
+#include <alloca.h>
+
+#include "unit_test.h"
+
+using namespace qpid::client;
+
+
+QPID_AUTO_TEST_SUITE(QueueOptionsTestSuite)
+
+QPID_AUTO_TEST_CASE(testSizePolicy)
+{
+ QueueOptions ft;
+
+ ft.setSizePolicy(REJECT,1,2);
+
+ BOOST_CHECK(QueueOptions::strREJECT == ft.getAsString(QueueOptions::strTypeKey));
+ BOOST_CHECK(1 == ft.getAsInt(QueueOptions::strMaxSizeKey));
+ BOOST_CHECK(2 == ft.getAsInt(QueueOptions::strMaxCountKey));
+
+ ft.setSizePolicy(FLOW_TO_DISK,0,2);
+ BOOST_CHECK(QueueOptions::strFLOW_TO_DISK == ft.getAsString(QueueOptions::strTypeKey));
+ BOOST_CHECK(1 == ft.getAsInt(QueueOptions::strMaxSizeKey));
+ BOOST_CHECK(2 == ft.getAsInt(QueueOptions::strMaxCountKey));
+
+ ft.setSizePolicy(RING,1,0);
+ BOOST_CHECK(QueueOptions::strRING == ft.getAsString(QueueOptions::strTypeKey));
+
+ ft.setSizePolicy(RING_STRICT,1,0);
+ BOOST_CHECK(QueueOptions::strRING_STRICT == ft.getAsString(QueueOptions::strTypeKey));
+
+ ft.clearSizePolicy();
+ BOOST_CHECK(!ft.isSet(QueueOptions::strTypeKey));
+ BOOST_CHECK(!ft.isSet(QueueOptions::strMaxSizeKey));
+ BOOST_CHECK(!ft.isSet(QueueOptions::strMaxCountKey));
+}
+
+QPID_AUTO_TEST_CASE(testFlags)
+{
+ QueueOptions ft;
+
+ ft.setPersistLastNode();
+ ft.setOrdering(LVQ);
+
+ BOOST_CHECK(1 == ft.getAsInt(QueueOptions::strPersistLastNode));
+ BOOST_CHECK(1 == ft.getAsInt(QueueOptions::strLastValueQueue));
+
+ ft.clearPersistLastNode();
+ ft.setOrdering(FIFO);
+
+ BOOST_CHECK(!ft.isSet(QueueOptions::strPersistLastNode));
+ BOOST_CHECK(!ft.isSet(QueueOptions::strLastValueQueue));
+
+}
+
+QPID_AUTO_TEST_CASE(testSetOrdering)
+{
+ //ensure setOrdering(FIFO) works even if not preceded by a call to
+ //setOrdering(LVQ)
+ QueueOptions ft;
+ ft.setOrdering(FIFO);
+ BOOST_CHECK(!ft.isSet(QueueOptions::strLastValueQueue));
+
+}
+
+QPID_AUTO_TEST_CASE(testClearPersistLastNode)
+{
+ //ensure clear works even if not preceded by the setting on the
+ //option
+ QueueOptions ft;
+ ft.clearPersistLastNode();
+ BOOST_CHECK(!ft.isSet(QueueOptions::strPersistLastNode));
+}
+
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/QueuePolicyTest.cpp b/RC9/qpid/cpp/src/tests/QueuePolicyTest.cpp
new file mode 100644
index 0000000000..6c650169c7
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/QueuePolicyTest.cpp
@@ -0,0 +1,274 @@
+ /*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "unit_test.h"
+#include "test_tools.h"
+
+#include "qpid/broker/QueuePolicy.h"
+#include "qpid/client/QueueOptions.h"
+#include "qpid/sys/Time.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "MessageUtils.h"
+#include "BrokerFixture.h"
+
+using namespace qpid::broker;
+using namespace qpid::client;
+using namespace qpid::framing;
+
+QPID_AUTO_TEST_SUITE(QueuePolicyTestSuite)
+
+QueuedMessage createMessage(uint32_t size)
+{
+ QueuedMessage msg;
+ msg.payload = MessageUtils::createMessage();
+ MessageUtils::addContent(msg.payload, std::string (size, 'x'));
+ return msg;
+}
+
+
+QPID_AUTO_TEST_CASE(testCount)
+{
+ std::auto_ptr<QueuePolicy> policy(QueuePolicy::createQueuePolicy(5, 0));
+ BOOST_CHECK_EQUAL((uint64_t) 0, policy->getMaxSize());
+ BOOST_CHECK_EQUAL((uint32_t) 5, policy->getMaxCount());
+
+ QueuedMessage msg = createMessage(10);
+ for (size_t i = 0; i < 5; i++) {
+ policy->tryEnqueue(msg);
+ }
+ try {
+ policy->tryEnqueue(msg);
+ BOOST_FAIL("Policy did not fail on enqueuing sixth message");
+ } catch (const ResourceLimitExceededException&) {}
+
+ policy->dequeued(msg);
+ policy->tryEnqueue(msg);
+
+ try {
+ policy->tryEnqueue(msg);
+ BOOST_FAIL("Policy did not fail on enqueuing sixth message (after dequeue)");
+ } catch (const ResourceLimitExceededException&) {}
+}
+
+QPID_AUTO_TEST_CASE(testSize)
+{
+ std::auto_ptr<QueuePolicy> policy(QueuePolicy::createQueuePolicy(0, 50));
+ QueuedMessage msg = createMessage(10);
+
+ for (size_t i = 0; i < 5; i++) {
+ policy->tryEnqueue(msg);
+ }
+ try {
+ policy->tryEnqueue(msg);
+ BOOST_FAIL("Policy did not fail on aggregate size exceeding 50. " << *policy);
+ } catch (const ResourceLimitExceededException&) {}
+
+ policy->dequeued(msg);
+ policy->tryEnqueue(msg);
+
+ try {
+ policy->tryEnqueue(msg);
+ BOOST_FAIL("Policy did not fail on aggregate size exceeding 50 (after dequeue). " << *policy);
+ } catch (const ResourceLimitExceededException&) {}
+}
+
+QPID_AUTO_TEST_CASE(testBoth)
+{
+ std::auto_ptr<QueuePolicy> policy(QueuePolicy::createQueuePolicy(5, 50));
+ try {
+ QueuedMessage msg = createMessage(51);
+ policy->tryEnqueue(msg);
+ BOOST_FAIL("Policy did not fail on single message exceeding 50. " << *policy);
+ } catch (const ResourceLimitExceededException&) {}
+
+ std::vector<QueuedMessage> messages;
+ messages.push_back(createMessage(15));
+ messages.push_back(createMessage(10));
+ messages.push_back(createMessage(11));
+ messages.push_back(createMessage(2));
+ messages.push_back(createMessage(7));
+ for (size_t i = 0; i < messages.size(); i++) {
+ policy->tryEnqueue(messages[i]);
+ }
+ //size = 45 at this point, count = 5
+ try {
+ QueuedMessage msg = createMessage(5);
+ policy->tryEnqueue(msg);
+ BOOST_FAIL("Policy did not fail on count exceeding 6. " << *policy);
+ } catch (const ResourceLimitExceededException&) {}
+ try {
+ QueuedMessage msg = createMessage(10);
+ policy->tryEnqueue(msg);
+ BOOST_FAIL("Policy did not fail on aggregate size exceeding 50. " << *policy);
+ } catch (const ResourceLimitExceededException&) {}
+
+
+ policy->dequeued(messages[0]);
+ try {
+ QueuedMessage msg = createMessage(20);
+ policy->tryEnqueue(msg);
+ } catch (const ResourceLimitExceededException&) {
+ BOOST_FAIL("Policy failed incorrectly after dequeue. " << *policy);
+ }
+}
+
+QPID_AUTO_TEST_CASE(testSettings)
+{
+ //test reading and writing the policy from/to field table
+ std::auto_ptr<QueuePolicy> a(QueuePolicy::createQueuePolicy(101, 303));
+ FieldTable settings;
+ a->update(settings);
+ std::auto_ptr<QueuePolicy> b(QueuePolicy::createQueuePolicy(settings));
+ BOOST_CHECK_EQUAL(a->getMaxCount(), b->getMaxCount());
+ BOOST_CHECK_EQUAL(a->getMaxSize(), b->getMaxSize());
+}
+
+QPID_AUTO_TEST_CASE(testRingPolicy)
+{
+ FieldTable args;
+ std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy(5, 0, QueuePolicy::RING);
+ policy->update(args);
+
+ ProxySessionFixture f;
+ std::string q("my-ring-queue");
+ f.session.queueDeclare(arg::queue=q, arg::exclusive=true, arg::autoDelete=true, arg::arguments=args);
+ for (int i = 0; i < 10; i++) {
+ f.session.messageTransfer(arg::content=client::Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), q));
+ }
+ client::Message msg;
+ for (int i = 5; i < 10; i++) {
+ BOOST_CHECK(f.subs.get(msg, q, qpid::sys::TIME_SEC));
+ BOOST_CHECK_EQUAL((boost::format("%1%_%2%") % "Message" % (i+1)).str(), msg.getData());
+ }
+ BOOST_CHECK(!f.subs.get(msg, q));
+}
+
+QPID_AUTO_TEST_CASE(testStrictRingPolicy)
+{
+ FieldTable args;
+ std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy(5, 0, QueuePolicy::RING_STRICT);
+ policy->update(args);
+
+ ProxySessionFixture f;
+ std::string q("my-ring-queue");
+ f.session.queueDeclare(arg::queue=q, arg::exclusive=true, arg::autoDelete=true, arg::arguments=args);
+ LocalQueue incoming;
+ SubscriptionSettings settings(FlowControl::unlimited());
+ settings.autoAck = 0; // no auto ack.
+ Subscription sub = f.subs.subscribe(incoming, q, settings);
+ for (int i = 0; i < 5; i++) {
+ f.session.messageTransfer(arg::content=client::Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), q));
+ }
+ for (int i = 0; i < 5; i++) {
+ BOOST_CHECK_EQUAL(incoming.pop().getData(), (boost::format("%1%_%2%") % "Message" % (i+1)).str());
+ }
+ try {
+ ScopedSuppressLogging sl; // Suppress messages for expected errors.
+ f.session.messageTransfer(arg::content=client::Message("Message_6", q));
+ BOOST_FAIL("expecting ResourceLimitExceededException.");
+ } catch (const ResourceLimitExceededException&) {}
+}
+
+QPID_AUTO_TEST_CASE(testPolicyWithDtx)
+{
+ FieldTable args;
+ std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy(5, 0, QueuePolicy::REJECT);
+ policy->update(args);
+
+ ProxySessionFixture f;
+ std::string q("my-policy-queue");
+ f.session.queueDeclare(arg::queue=q, arg::exclusive=true, arg::autoDelete=true, arg::arguments=args);
+ LocalQueue incoming;
+ SubscriptionSettings settings(FlowControl::unlimited());
+ settings.autoAck = 0; // no auto ack.
+ Subscription sub = f.subs.subscribe(incoming, q, settings);
+ f.session.dtxSelect();
+ Xid tx1(1, "test-dtx-mgr", "tx1");
+ f.session.dtxStart(arg::xid=tx1);
+ for (int i = 0; i < 5; i++) {
+ f.session.messageTransfer(arg::content=client::Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), q));
+ }
+ f.session.dtxEnd(arg::xid=tx1);
+ f.session.dtxCommit(arg::xid=tx1, arg::onePhase=true);
+
+ Xid tx2(1, "test-dtx-mgr", "tx2");
+ f.session.dtxStart(arg::xid=tx2);
+ for (int i = 0; i < 5; i++) {
+ BOOST_CHECK_EQUAL(incoming.pop().getData(), (boost::format("%1%_%2%") % "Message" % (i+1)).str());
+ }
+ SequenceSet accepting=sub.getUnaccepted();
+ f.session.messageAccept(accepting);
+ f.session.dtxEnd(arg::xid=tx2);
+ f.session.dtxPrepare(arg::xid=tx2);
+ f.session.dtxRollback(arg::xid=tx2);
+ f.session.messageRelease(accepting);
+
+ Xid tx3(1, "test-dtx-mgr", "tx3");
+ f.session.dtxStart(arg::xid=tx3);
+ for (int i = 0; i < 5; i++) {
+ incoming.pop();
+ }
+ accepting=sub.getUnaccepted();
+ f.session.messageAccept(accepting);
+ f.session.dtxEnd(arg::xid=tx3);
+ f.session.dtxPrepare(arg::xid=tx3);
+
+ Session other = f.connection.newSession();
+ try {
+ ScopedSuppressLogging sl; // Suppress messages for expected errors.
+ other.messageTransfer(arg::content=client::Message("Message_6", q));
+ BOOST_FAIL("expecting ResourceLimitExceededException.");
+ } catch (const ResourceLimitExceededException&) {}
+
+ f.session.dtxCommit(arg::xid=tx3);
+ //now retry and this time should succeed
+ other = f.connection.newSession();
+ other.messageTransfer(arg::content=client::Message("Message_6", q));
+}
+
+QPID_AUTO_TEST_CASE(testFlowToDiskWithNoStore)
+{
+ //Ensure that with no store loaded, we don't flow to disk but
+ //fallback to rejecting messages
+ QueueOptions args;
+ args.setSizePolicy(FLOW_TO_DISK, 0, 5);
+
+ ProxySessionFixture f;
+ std::string q("my-queue");
+ f.session.queueDeclare(arg::queue=q, arg::exclusive=true, arg::autoDelete=true, arg::arguments=args);
+ LocalQueue incoming;
+ SubscriptionSettings settings(FlowControl::unlimited());
+ settings.autoAck = 0; // no auto ack.
+ Subscription sub = f.subs.subscribe(incoming, q, settings);
+ for (int i = 0; i < 5; i++) {
+ f.session.messageTransfer(arg::content=client::Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), q));
+ }
+ for (int i = 0; i < 5; i++) {
+ BOOST_CHECK_EQUAL(incoming.pop().getData(), (boost::format("%1%_%2%") % "Message" % (i+1)).str());
+ }
+ try {
+ ScopedSuppressLogging sl; // Suppress messages for expected errors.
+ f.session.messageTransfer(arg::content=client::Message("Message_6", q));
+ BOOST_FAIL("expecting ResourceLimitExceededException.");
+ } catch (const ResourceLimitExceededException&) {}
+}
+
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/QueueRegistryTest.cpp b/RC9/qpid/cpp/src/tests/QueueRegistryTest.cpp
new file mode 100644
index 0000000000..7ad4e0b89d
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/QueueRegistryTest.cpp
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "qpid/broker/QueueRegistry.h"
+#include "unit_test.h"
+#include <string>
+
+using namespace qpid::broker;
+
+QPID_AUTO_TEST_SUITE(QueueRegistryTest)
+
+QPID_AUTO_TEST_CASE(testDeclare)
+{
+ std::string foo("foo");
+ std::string bar("bar");
+ QueueRegistry reg;
+ std::pair<Queue::shared_ptr, bool> qc;
+
+ qc = reg.declare(foo, false, 0, 0);
+ Queue::shared_ptr q = qc.first;
+ BOOST_CHECK(q);
+ BOOST_CHECK(qc.second); // New queue
+ BOOST_CHECK_EQUAL(foo, q->getName());
+
+ qc = reg.declare(foo, false, 0, 0);
+ BOOST_CHECK_EQUAL(q, qc.first);
+ BOOST_CHECK(!qc.second);
+
+ qc = reg.declare(bar, false, 0, 0);
+ q = qc.first;
+ BOOST_CHECK(q);
+ BOOST_CHECK_EQUAL(true, qc.second);
+ BOOST_CHECK_EQUAL(bar, q->getName());
+}
+
+QPID_AUTO_TEST_CASE(testDeclareTmp)
+{
+ QueueRegistry reg;
+ std::pair<Queue::shared_ptr, bool> qc;
+
+ qc = reg.declare(std::string(), false, 0, 0);
+ BOOST_CHECK(qc.second);
+ BOOST_CHECK_EQUAL(std::string("tmp_1"), qc.first->getName());
+}
+
+QPID_AUTO_TEST_CASE(testFind)
+{
+ std::string foo("foo");
+ std::string bar("bar");
+ QueueRegistry reg;
+ std::pair<Queue::shared_ptr, bool> qc;
+
+ BOOST_CHECK(reg.find(foo) == 0);
+
+ reg.declare(foo, false, 0, 0);
+ reg.declare(bar, false, 0, 0);
+ Queue::shared_ptr q = reg.find(bar);
+ BOOST_CHECK(q);
+ BOOST_CHECK_EQUAL(bar, q->getName());
+}
+
+QPID_AUTO_TEST_CASE(testDestroy)
+{
+ std::string foo("foo");
+ QueueRegistry reg;
+ std::pair<Queue::shared_ptr, bool> qc;
+
+ qc = reg.declare(foo, false, 0, 0);
+ reg.destroy(foo);
+ // Queue is gone from the registry.
+ BOOST_CHECK(reg.find(foo) == 0);
+ // Queue is not actually destroyed till we drop our reference.
+ BOOST_CHECK_EQUAL(foo, qc.first->getName());
+ // We shoud be the only reference.
+ BOOST_CHECK_EQUAL(1L, qc.first.use_count());
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/QueueTest.cpp b/RC9/qpid/cpp/src/tests/QueueTest.cpp
new file mode 100644
index 0000000000..f1771e26cd
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/QueueTest.cpp
@@ -0,0 +1,501 @@
+ /*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "unit_test.h"
+#include "qpid/Exception.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/broker/Queue.h"
+#include "qpid/broker/Deliverable.h"
+#include "qpid/broker/ExchangeRegistry.h"
+#include "qpid/broker/QueueRegistry.h"
+#include "qpid/broker/NullMessageStore.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/client/QueueOptions.h"
+#include <iostream>
+#include "boost/format.hpp"
+
+using boost::intrusive_ptr;
+using namespace qpid;
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+class TestConsumer : public virtual Consumer{
+public:
+ typedef boost::shared_ptr<TestConsumer> shared_ptr;
+
+ intrusive_ptr<Message> last;
+ bool received;
+ TestConsumer(bool acquire = true):Consumer(acquire), received(false) {};
+
+ virtual bool deliver(QueuedMessage& msg){
+ last = msg.payload;
+ received = true;
+ return true;
+ };
+ void notify() {}
+ OwnershipToken* getSession() { return 0; }
+};
+
+class FailOnDeliver : public Deliverable
+{
+ Message msg;
+public:
+ void deliverTo(const boost::shared_ptr<Queue>& queue)
+ {
+ throw Exception(QPID_MSG("Invalid delivery to " << queue->getName()));
+ }
+ Message& getMessage() { return msg; }
+};
+
+intrusive_ptr<Message> create_message(std::string exchange, std::string routingKey) {
+ intrusive_ptr<Message> msg(new Message());
+ AMQFrame method(in_place<MessageTransferBody>(ProtocolVersion(), exchange, 0, 0));
+ AMQFrame header(in_place<AMQHeaderBody>());
+ msg->getFrames().append(method);
+ msg->getFrames().append(header);
+ msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setRoutingKey(routingKey);
+ return msg;
+}
+
+QPID_AUTO_TEST_SUITE(QueueTestSuite)
+
+QPID_AUTO_TEST_CASE(testAsyncMessage) {
+ Queue::shared_ptr queue(new Queue("my_test_queue", true));
+ intrusive_ptr<Message> received;
+
+ TestConsumer::shared_ptr c1(new TestConsumer());
+ queue->consume(c1);
+
+
+ //Test basic delivery:
+ intrusive_ptr<Message> msg1 = create_message("e", "A");
+ msg1->enqueueAsync();//this is done on enqueue which is not called from process
+ queue->process(msg1);
+ sleep(2);
+
+ BOOST_CHECK(!c1->received);
+ msg1->enqueueComplete();
+
+ received = queue->get().payload;
+ BOOST_CHECK_EQUAL(msg1.get(), received.get());
+}
+
+
+QPID_AUTO_TEST_CASE(testAsyncMessageCount){
+ Queue::shared_ptr queue(new Queue("my_test_queue", true));
+ intrusive_ptr<Message> msg1 = create_message("e", "A");
+ msg1->enqueueAsync();//this is done on enqueue which is not called from process
+
+ queue->process(msg1);
+ sleep(2);
+ uint32_t compval=0;
+ BOOST_CHECK_EQUAL(compval, queue->getMessageCount());
+ msg1->enqueueComplete();
+ compval=1;
+ BOOST_CHECK_EQUAL(compval, queue->getMessageCount());
+}
+
+QPID_AUTO_TEST_CASE(testConsumers){
+ Queue::shared_ptr queue(new Queue("my_queue", true));
+
+ //Test adding consumers:
+ TestConsumer::shared_ptr c1(new TestConsumer());
+ TestConsumer::shared_ptr c2(new TestConsumer());
+ queue->consume(c1);
+ queue->consume(c2);
+
+ BOOST_CHECK_EQUAL(uint32_t(2), queue->getConsumerCount());
+
+ //Test basic delivery:
+ intrusive_ptr<Message> msg1 = create_message("e", "A");
+ intrusive_ptr<Message> msg2 = create_message("e", "B");
+ intrusive_ptr<Message> msg3 = create_message("e", "C");
+
+ queue->deliver(msg1);
+ BOOST_CHECK(queue->dispatch(c1));
+ BOOST_CHECK_EQUAL(msg1.get(), c1->last.get());
+
+ queue->deliver(msg2);
+ BOOST_CHECK(queue->dispatch(c2));
+ BOOST_CHECK_EQUAL(msg2.get(), c2->last.get());
+
+ c1->received = false;
+ queue->deliver(msg3);
+ BOOST_CHECK(queue->dispatch(c1));
+ BOOST_CHECK_EQUAL(msg3.get(), c1->last.get());
+
+ //Test cancellation:
+ queue->cancel(c1);
+ BOOST_CHECK_EQUAL(uint32_t(1), queue->getConsumerCount());
+ queue->cancel(c2);
+ BOOST_CHECK_EQUAL(uint32_t(0), queue->getConsumerCount());
+}
+
+QPID_AUTO_TEST_CASE(testRegistry){
+ //Test use of queues in registry:
+ QueueRegistry registry;
+ registry.declare("queue1", true, true);
+ registry.declare("queue2", true, true);
+ registry.declare("queue3", true, true);
+
+ BOOST_CHECK(registry.find("queue1"));
+ BOOST_CHECK(registry.find("queue2"));
+ BOOST_CHECK(registry.find("queue3"));
+
+ registry.destroy("queue1");
+ registry.destroy("queue2");
+ registry.destroy("queue3");
+
+ BOOST_CHECK(!registry.find("queue1"));
+ BOOST_CHECK(!registry.find("queue2"));
+ BOOST_CHECK(!registry.find("queue3"));
+}
+
+QPID_AUTO_TEST_CASE(testDequeue){
+ Queue::shared_ptr queue(new Queue("my_queue", true));
+ intrusive_ptr<Message> msg1 = create_message("e", "A");
+ intrusive_ptr<Message> msg2 = create_message("e", "B");
+ intrusive_ptr<Message> msg3 = create_message("e", "C");
+ intrusive_ptr<Message> received;
+
+ queue->deliver(msg1);
+ queue->deliver(msg2);
+ queue->deliver(msg3);
+
+ BOOST_CHECK_EQUAL(uint32_t(3), queue->getMessageCount());
+
+ received = queue->get().payload;
+ BOOST_CHECK_EQUAL(msg1.get(), received.get());
+ BOOST_CHECK_EQUAL(uint32_t(2), queue->getMessageCount());
+
+ received = queue->get().payload;
+ BOOST_CHECK_EQUAL(msg2.get(), received.get());
+ BOOST_CHECK_EQUAL(uint32_t(1), queue->getMessageCount());
+
+ TestConsumer::shared_ptr consumer(new TestConsumer());
+ queue->consume(consumer);
+ queue->dispatch(consumer);
+ if (!consumer->received)
+ sleep(2);
+
+ BOOST_CHECK_EQUAL(msg3.get(), consumer->last.get());
+ BOOST_CHECK_EQUAL(uint32_t(0), queue->getMessageCount());
+
+ received = queue->get().payload;
+ BOOST_CHECK(!received);
+ BOOST_CHECK_EQUAL(uint32_t(0), queue->getMessageCount());
+
+}
+
+QPID_AUTO_TEST_CASE(testBound)
+{
+ //test the recording of bindings, and use of those to allow a queue to be unbound
+ string key("my-key");
+ FieldTable args;
+
+ Queue::shared_ptr queue(new Queue("my-queue", true));
+ ExchangeRegistry exchanges;
+ //establish bindings from exchange->queue and notify the queue as it is bound:
+ Exchange::shared_ptr exchange1 = exchanges.declare("my-exchange-1", "direct").first;
+ exchange1->bind(queue, key, &args);
+ queue->bound(exchange1->getName(), key, args);
+
+ Exchange::shared_ptr exchange2 = exchanges.declare("my-exchange-2", "fanout").first;
+ exchange2->bind(queue, key, &args);
+ queue->bound(exchange2->getName(), key, args);
+
+ Exchange::shared_ptr exchange3 = exchanges.declare("my-exchange-3", "topic").first;
+ exchange3->bind(queue, key, &args);
+ queue->bound(exchange3->getName(), key, args);
+
+ //delete one of the exchanges:
+ exchanges.destroy(exchange2->getName());
+ exchange2.reset();
+
+ //unbind the queue from all exchanges it knows it has been bound to:
+ queue->unbind(exchanges, queue);
+
+ //ensure the remaining exchanges don't still have the queue bound to them:
+ FailOnDeliver deliverable;
+ exchange1->route(deliverable, key, &args);
+ exchange3->route(deliverable, key, &args);
+}
+
+QPID_AUTO_TEST_CASE(testPersistLastNodeStanding){
+
+ client::QueueOptions args;
+ args.setPersistLastNode();
+
+ Queue::shared_ptr queue(new Queue("my-queue", true));
+ queue->configure(args);
+
+ intrusive_ptr<Message> msg1 = create_message("e", "A");
+ intrusive_ptr<Message> msg2 = create_message("e", "B");
+ intrusive_ptr<Message> msg3 = create_message("e", "C");
+
+ //enqueue 2 messages
+ queue->deliver(msg1);
+ queue->deliver(msg2);
+
+ //change mode
+ queue->setLastNodeFailure();
+
+ //enqueue 1 message
+ queue->deliver(msg3);
+
+ //check all have persistent ids.
+ BOOST_CHECK(msg1->isPersistent());
+ BOOST_CHECK(msg2->isPersistent());
+ BOOST_CHECK(msg3->isPersistent());
+
+}
+
+class TestMessageStoreOC : public NullMessageStore
+{
+ public:
+
+ virtual void dequeue(TransactionContext*,
+ const boost::intrusive_ptr<PersistableMessage>& /*msg*/,
+ const PersistableQueue& /*queue*/)
+ {
+ }
+
+ virtual void enqueue(TransactionContext*,
+ const boost::intrusive_ptr<PersistableMessage>& /*msg*/,
+ const PersistableQueue& /* queue */)
+ {
+ }
+
+ TestMessageStoreOC() : NullMessageStore() {}
+ ~TestMessageStoreOC(){}
+};
+
+
+QPID_AUTO_TEST_CASE(testLVQOrdering){
+
+ client::QueueOptions args;
+ // set queue mode
+ args.setOrdering(client::LVQ);
+
+ Queue::shared_ptr queue(new Queue("my-queue", true ));
+ queue->configure(args);
+
+ intrusive_ptr<Message> msg1 = create_message("e", "A");
+ intrusive_ptr<Message> msg2 = create_message("e", "B");
+ intrusive_ptr<Message> msg3 = create_message("e", "C");
+ intrusive_ptr<Message> msg4 = create_message("e", "D");
+ intrusive_ptr<Message> received;
+
+ //set deliever match for LVQ a,b,c,a
+
+ string key;
+ args.getLVQKey(key);
+ BOOST_CHECK_EQUAL(key, "qpid.LVQ_key");
+
+
+ msg1->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
+ msg2->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"b");
+ msg3->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"c");
+ msg4->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
+
+ //enqueue 4 message
+ queue->deliver(msg1);
+ queue->deliver(msg2);
+ queue->deliver(msg3);
+ queue->deliver(msg4);
+
+ BOOST_CHECK_EQUAL(queue->getMessageCount(), 3u);
+
+ received = queue->get().payload;
+ BOOST_CHECK_EQUAL(msg4.get(), received.get());
+
+ received = queue->get().payload;
+ BOOST_CHECK_EQUAL(msg2.get(), received.get());
+
+ received = queue->get().payload;
+ BOOST_CHECK_EQUAL(msg3.get(), received.get());
+
+ intrusive_ptr<Message> msg5 = create_message("e", "A");
+ intrusive_ptr<Message> msg6 = create_message("e", "B");
+ intrusive_ptr<Message> msg7 = create_message("e", "C");
+ msg5->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
+ msg6->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"b");
+ msg7->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"c");
+ queue->deliver(msg5);
+ queue->deliver(msg6);
+ queue->deliver(msg7);
+
+ BOOST_CHECK_EQUAL(queue->getMessageCount(), 3u);
+
+ received = queue->get().payload;
+ BOOST_CHECK_EQUAL(msg5.get(), received.get());
+
+ received = queue->get().payload;
+ BOOST_CHECK_EQUAL(msg6.get(), received.get());
+
+ received = queue->get().payload;
+ BOOST_CHECK_EQUAL(msg7.get(), received.get());
+
+}
+
+QPID_AUTO_TEST_CASE(testLVQAcquire){
+
+ client::QueueOptions args;
+ // set queue mode
+ args.setOrdering(client::LVQ);
+
+ Queue::shared_ptr queue(new Queue("my-queue", true ));
+ queue->configure(args);
+
+ intrusive_ptr<Message> msg1 = create_message("e", "A");
+ intrusive_ptr<Message> msg2 = create_message("e", "B");
+ intrusive_ptr<Message> msg3 = create_message("e", "C");
+ intrusive_ptr<Message> msg4 = create_message("e", "D");
+ intrusive_ptr<Message> msg5 = create_message("e", "F");
+ intrusive_ptr<Message> msg6 = create_message("e", "G");
+
+ //set deliever match for LVQ a,b,c,a
+
+ string key;
+ args.getLVQKey(key);
+ BOOST_CHECK_EQUAL(key, "qpid.LVQ_key");
+
+
+ msg1->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
+ msg2->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"b");
+ msg3->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"c");
+ msg4->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
+ msg5->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"b");
+ msg6->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"c");
+
+ //enqueue 4 message
+ queue->deliver(msg1);
+ queue->deliver(msg2);
+ queue->deliver(msg3);
+ queue->deliver(msg4);
+
+ BOOST_CHECK_EQUAL(queue->getMessageCount(), 3u);
+
+ framing::SequenceNumber sequence(1);
+ QueuedMessage qmsg(queue.get(), msg1, sequence);
+ QueuedMessage qmsg2(queue.get(), msg2, ++sequence);
+
+ BOOST_CHECK(!queue->acquire(qmsg));
+ BOOST_CHECK(queue->acquire(qmsg2));
+
+ BOOST_CHECK_EQUAL(queue->getMessageCount(), 2u);
+
+ queue->deliver(msg5);
+ BOOST_CHECK_EQUAL(queue->getMessageCount(), 3u);
+
+ // set mode to no browse and check
+ args.setOrdering(client::LVQ_NO_BROWSE);
+ queue->configure(args);
+ TestConsumer::shared_ptr c1(new TestConsumer(false));
+
+ queue->dispatch(c1);
+ queue->dispatch(c1);
+ queue->dispatch(c1);
+
+ queue->deliver(msg6);
+ BOOST_CHECK_EQUAL(queue->getMessageCount(), 3u);
+
+ intrusive_ptr<Message> received;
+ received = queue->get().payload;
+ BOOST_CHECK_EQUAL(msg4.get(), received.get());
+
+}
+
+QPID_AUTO_TEST_CASE(testLVQMultiQueue){
+
+ client::QueueOptions args;
+ // set queue mode
+ args.setOrdering(client::LVQ);
+
+ Queue::shared_ptr queue1(new Queue("my-queue", true ));
+ Queue::shared_ptr queue2(new Queue("my-queue", true ));
+ intrusive_ptr<Message> received;
+ queue1->configure(args);
+ queue2->configure(args);
+
+ intrusive_ptr<Message> msg1 = create_message("e", "A");
+ intrusive_ptr<Message> msg2 = create_message("e", "A");
+
+ string key;
+ args.getLVQKey(key);
+ BOOST_CHECK_EQUAL(key, "qpid.LVQ_key");
+
+ msg1->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
+ msg2->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
+
+ queue1->deliver(msg1);
+ queue2->deliver(msg1);
+ queue1->deliver(msg2);
+
+ received = queue1->get().payload;
+ BOOST_CHECK_EQUAL(msg2.get(), received.get());
+
+ received = queue2->get().payload;
+ BOOST_CHECK_EQUAL(msg1.get(), received.get());
+
+}
+
+void addMessagesToQueue(uint count, Queue& queue, uint oddTtl = 200, uint evenTtl = 0)
+{
+ for (uint i = 0; i < count; i++) {
+ intrusive_ptr<Message> m = create_message("exchange", "key");
+ if (i % 2) {
+ if (oddTtl) m->getProperties<DeliveryProperties>()->setTtl(oddTtl);
+ } else {
+ if (evenTtl) m->getProperties<DeliveryProperties>()->setTtl(evenTtl);
+ }
+ m->setTimestamp();
+ queue.deliver(m);
+ }
+}
+
+QPID_AUTO_TEST_CASE(testPurgeExpired) {
+ Queue queue("my-queue");
+ addMessagesToQueue(10, queue);
+ BOOST_CHECK_EQUAL(queue.getMessageCount(), 10u);
+ ::usleep(300*1000);
+ queue.purgeExpired();
+ BOOST_CHECK_EQUAL(queue.getMessageCount(), 5u);
+}
+
+QPID_AUTO_TEST_CASE(testQueueCleaner) {
+ Timer timer;
+ QueueRegistry queues;
+ Queue::shared_ptr queue = queues.declare("my-queue").first;
+ addMessagesToQueue(10, *queue, 200, 400);
+ BOOST_CHECK_EQUAL(queue->getMessageCount(), 10u);
+
+ QueueCleaner cleaner(queues, timer);
+ cleaner.start(100 * qpid::sys::TIME_MSEC);
+ ::usleep(300*1000);
+ BOOST_CHECK_EQUAL(queue->getMessageCount(), 5u);
+ ::usleep(300*1000);
+ BOOST_CHECK_EQUAL(queue->getMessageCount(), 0u);
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+
diff --git a/RC9/qpid/cpp/src/tests/README b/RC9/qpid/cpp/src/tests/README
new file mode 100644
index 0000000000..0f4edee493
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/README
@@ -0,0 +1,54 @@
+= Running Qpid C++ tests =
+
+General philosophy is that "make check" run all tests by default, but
+developers can run tests selectively as explained below.
+
+== Valgrind ==
+
+By default we run tests under valgrind to detect memory errors if valgrind
+is present. ./configure --disable-valgrind will disable it.
+
+Default valgrind options are specified in .valgrindrc-default, which a
+checked-in file. The actual options used are in .valgrindrc which is a
+local file. Normally it is a copy of valgrindrc-default but you can
+modify at will.
+
+Supressed errors are listed in .valgrind.supp. If you want to change
+suppressions for local testing, just modify .valgrindrc to point to a
+different file. Do NOT add suppressions to .valgrindrc.supp unless
+they are known problems outside of Qpid that can't reasonably be
+worked around in Qpid.
+
+
+== Unit Tests ==
+Unit tests use the boost test framework, and are compiled to rogram
+ unit_test
+There are several options to control how test results are displayed,
+see
+ http://www.boost.org/doc/libs/1_35_0/libs/test/doc/components/utf/parameters/index.html
+
+NOTE: some unit tests are written as CppUnit plug-ins, we are moving away
+from CppUnit so new tests should use the boost framework.
+
+CppUnit tests are run by the script run-unit-tests.
+
+== System Tests ==
+
+System tests are self contained AMQP client executables or scripts.
+They are listed in the TESTS make variable, which can be over-ridden.
+
+The ./start_broker "test" launches the broker, ./stop_broker" stops it.
+Tests in between assume the broker is running.
+
+./python_tests: runs ../python/run_tests. This is the main set of
+system testss for the broker.
+
+Other C++ client test executables and scripts under client/test are
+system tests for the client.
+
+By setting TESTS in a make command you can run a different subset of tests
+against an already-running broker.
+
+
+
+
diff --git a/RC9/qpid/cpp/src/tests/RangeSet.cpp b/RC9/qpid/cpp/src/tests/RangeSet.cpp
new file mode 100644
index 0000000000..9c602de78d
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/RangeSet.cpp
@@ -0,0 +1,141 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+#include "unit_test.h"
+#include "test_tools.h"
+#include "qpid/RangeSet.h"
+
+using namespace std;
+using namespace qpid;
+
+QPID_AUTO_TEST_SUITE(RangeSetTestSuite)
+
+typedef qpid::Range<int> TestRange;
+typedef qpid::RangeSet<int> TestRangeSet;
+
+QPID_AUTO_TEST_CASE(testEmptyRange) {
+ TestRange r;
+ BOOST_CHECK(r.empty());
+ BOOST_CHECK(!r.contains(0));
+ // BOOST_CHECK(r.contiguous(0));
+}
+
+QPID_AUTO_TEST_CASE(testRangeSetAddPoint) {
+ TestRangeSet r;
+ BOOST_CHECK(r.empty());
+ r += 3;
+ BOOST_CHECK_MESSAGE(r.contains(3), r);
+ BOOST_CHECK_MESSAGE(r.contains(TestRange(3,4)), r);
+ BOOST_CHECK(!r.empty());
+ r += 5;
+ BOOST_CHECK_MESSAGE(r.contains(5), r);
+ BOOST_CHECK_MESSAGE(r.contains(TestRange(5,6)), r);
+ BOOST_CHECK_MESSAGE(!r.contains(TestRange(3,6)), r);
+ r += 4;
+ BOOST_CHECK_MESSAGE(r.contains(TestRange(3,6)), r);
+}
+
+QPID_AUTO_TEST_CASE(testRangeSetAddRange) {
+ TestRangeSet r;
+ r += TestRange(0,3);
+ BOOST_CHECK(r.contains(TestRange(0,3)));
+ r += TestRange(4,6);
+ BOOST_CHECK_MESSAGE(r.contains(TestRange(4,6)), r);
+ r += 3;
+ BOOST_CHECK_MESSAGE(r.contains(TestRange(0,6)), r);
+ BOOST_CHECK(r.front() == 0);
+ BOOST_CHECK(r.back() == 6);
+}
+
+QPID_AUTO_TEST_CASE(testRangeSetAddSet) {
+ TestRangeSet r;
+ TestRangeSet s = TestRangeSet(0,3)+TestRange(5,10);
+ r += s;
+ BOOST_CHECK_EQUAL(r,s);
+ r += TestRangeSet(3,5) + TestRange(7,12) + 15;
+ BOOST_CHECK_EQUAL(r, TestRangeSet(0,12) + 15);
+
+ r.clear();
+ BOOST_CHECK(r.empty());
+ r += TestRange::makeClosed(6,10);
+ BOOST_CHECK_EQUAL(r, TestRangeSet(6,11));
+ r += TestRangeSet(2,6)+8;
+ BOOST_CHECK_EQUAL(r, TestRangeSet(2,11));
+}
+
+QPID_AUTO_TEST_CASE(testRangeSetIterate) {
+ TestRangeSet r;
+ (((r += 1) += 10) += TestRange(4,7)) += 2;
+ BOOST_MESSAGE(r);
+ std::vector<int> actual;
+ std::copy(r.begin(), r.end(), std::back_inserter(actual));
+ std::vector<int> expect = boost::assign::list_of(1)(2)(4)(5)(6)(10);
+ BOOST_CHECK_EQUAL(expect, actual);
+}
+
+QPID_AUTO_TEST_CASE(testRangeSetRemove) {
+ // points
+ BOOST_CHECK_EQUAL(TestRangeSet(0,5)-3, TestRangeSet(0,3)+TestRange(4,5));
+ BOOST_CHECK_EQUAL(TestRangeSet(1,5)-5, TestRangeSet(1,5));
+ BOOST_CHECK_EQUAL(TestRangeSet(1,5)-0, TestRangeSet(1,5));
+
+ TestRangeSet r(TestRangeSet(0,5)+TestRange(10,15)+TestRange(20,25));
+
+ // TestRanges
+ BOOST_CHECK_EQUAL(r-TestRange(0,5), TestRangeSet(10,15)+TestRange(20,25));
+ BOOST_CHECK_EQUAL(r-TestRange(10,15), TestRangeSet(0,5)+TestRange(20,25));
+ BOOST_CHECK_EQUAL(r-TestRange(20,25), TestRangeSet(0,5)+TestRange(10,15));
+
+ BOOST_CHECK_EQUAL(r-TestRange(-5, 30), TestRangeSet());
+
+ BOOST_CHECK_EQUAL(r-TestRange(-5, 7), TestRangeSet(10,15)+TestRange(20,25));
+ BOOST_CHECK_EQUAL(r-TestRange(8,19), TestRangeSet(0,5)+TestRange(20,25));
+ BOOST_CHECK_EQUAL(r-TestRange(17,30), TestRangeSet(0,5)+TestRange(10,15));
+ BOOST_CHECK_EQUAL(r-TestRange(17,30), TestRangeSet(0,5)+TestRange(10,15));
+
+ BOOST_CHECK_EQUAL(r-TestRange(-5, 5), TestRangeSet(10,15)+TestRange(20,25));
+ BOOST_CHECK_EQUAL(r-TestRange(10,19), TestRangeSet(0,5)+TestRange(20,25));
+ BOOST_CHECK_EQUAL(r-TestRange(18,25), TestRangeSet(0,5)+TestRange(10,15));
+ BOOST_CHECK_EQUAL(r-TestRange(23,25), TestRangeSet(0,5)+TestRange(10,15)+TestRange(20,23));
+
+ BOOST_CHECK_EQUAL(r-TestRange(-3, 3), TestRangeSet(3,5)+TestRange(10,15)+TestRange(20,25));
+ BOOST_CHECK_EQUAL(r-TestRange(3, 7), TestRangeSet(0,2)+TestRange(10,15)+TestRange(20,25));
+ BOOST_CHECK_EQUAL(r-TestRange(3, 12), TestRangeSet(0,3)+TestRange(12,15)+TestRange(20,25));
+ BOOST_CHECK_EQUAL(r-TestRange(3, 22), TestRangeSet(12,15)+TestRange(22,25));
+ BOOST_CHECK_EQUAL(r-TestRange(12, 22), TestRangeSet(0,5)+TestRange(10,11)+TestRange(22,25));
+
+ // Sets
+ BOOST_CHECK_EQUAL(r-(TestRangeSet(-1,6)+TestRange(11,14)+TestRange(23,25)),
+ TestRangeSet(10,11)+TestRange(14,15)+TestRange(20,23));
+}
+
+QPID_AUTO_TEST_CASE(testRangeContaining) {
+ TestRangeSet r;
+ (((r += 1) += TestRange(3,5)) += 7);
+ BOOST_CHECK_EQUAL(r.rangeContaining(0), TestRange(0,0));
+ BOOST_CHECK_EQUAL(r.rangeContaining(1), TestRange(1,2));
+ BOOST_CHECK_EQUAL(r.rangeContaining(2), TestRange(2,2));
+ BOOST_CHECK_EQUAL(r.rangeContaining(3), TestRange(3,5));
+ BOOST_CHECK_EQUAL(r.rangeContaining(4), TestRange(3,5));
+ BOOST_CHECK_EQUAL(r.rangeContaining(5), TestRange(5,5));
+ BOOST_CHECK_EQUAL(r.rangeContaining(6), TestRange(6,6));
+ BOOST_CHECK_EQUAL(r.rangeContaining(7), TestRange(7,8));
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/RefCounted.cpp b/RC9/qpid/cpp/src/tests/RefCounted.cpp
new file mode 100644
index 0000000000..8c679a3d2e
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/RefCounted.cpp
@@ -0,0 +1,50 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/RefCounted.h"
+#include <boost/intrusive_ptr.hpp>
+
+#include "unit_test.h"
+
+QPID_AUTO_TEST_SUITE(RefCountedTestSuiteTestSuite)
+
+using boost::intrusive_ptr;
+using namespace std;
+using namespace qpid;
+
+struct CountMe : public RefCounted {
+ static int instances;
+ CountMe() { ++instances; }
+ ~CountMe() { --instances; }
+};
+
+int CountMe::instances=0;
+
+QPID_AUTO_TEST_CASE(testRefCounted) {
+ BOOST_CHECK_EQUAL(0, CountMe::instances);
+ intrusive_ptr<CountMe> p(new CountMe());
+ BOOST_CHECK_EQUAL(1, CountMe::instances);
+ intrusive_ptr<CountMe> q(p);
+ BOOST_CHECK_EQUAL(1, CountMe::instances);
+ q=0;
+ BOOST_CHECK_EQUAL(1, CountMe::instances);
+ p=0;
+ BOOST_CHECK_EQUAL(0, CountMe::instances);
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/SequenceNumberTest.cpp b/RC9/qpid/cpp/src/tests/SequenceNumberTest.cpp
new file mode 100644
index 0000000000..e4c6d066ef
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/SequenceNumberTest.cpp
@@ -0,0 +1,205 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "unit_test.h"
+#include <iostream>
+#include "qpid/framing/SequenceNumber.h"
+#include "qpid/framing/SequenceNumberSet.h"
+
+using namespace qpid::framing;
+
+
+void checkDifference(SequenceNumber& a, SequenceNumber& b, int gap)
+{
+ BOOST_CHECK_EQUAL(gap, a - b);
+ BOOST_CHECK_EQUAL(-gap, b - a);
+
+ //increment until b wraps around
+ for (int i = 0; i < (gap + 2); i++, ++a, ++b) {
+ BOOST_CHECK_EQUAL(gap, a - b);
+ }
+ //keep incrementing until a also wraps around
+ for (int i = 0; i < (gap + 2); i++, ++a, ++b) {
+ BOOST_CHECK_EQUAL(gap, a - b);
+ }
+ //let b catch up and overtake
+ for (int i = 0; i < (gap*2); i++, ++b) {
+ BOOST_CHECK_EQUAL(gap - i, a - b);
+ BOOST_CHECK_EQUAL(i - gap, b - a);
+ }
+}
+
+void checkComparison(SequenceNumber& a, SequenceNumber& b, int gap)
+{
+ //increment until b wraps around
+ for (int i = 0; i < (gap + 2); i++) {
+ BOOST_CHECK(++a < ++b);//test prefix
+ }
+ //keep incrementing until a also wraps around
+ for (int i = 0; i < (gap + 2); i++) {
+ BOOST_CHECK(a++ < b++);//test postfix
+ }
+ //let a 'catch up'
+ for (int i = 0; i < gap; i++) {
+ a++;
+ }
+ BOOST_CHECK(a == b);
+ BOOST_CHECK(++a > b);
+}
+
+
+QPID_AUTO_TEST_SUITE(SequenceNumberTestSuite)
+
+QPID_AUTO_TEST_CASE(testIncrementPostfix)
+{
+ SequenceNumber a;
+ SequenceNumber b;
+ BOOST_CHECK(!(a > b));
+ BOOST_CHECK(!(b < a));
+ BOOST_CHECK(a == b);
+
+ SequenceNumber c = a++;
+ BOOST_CHECK(a > b);
+ BOOST_CHECK(b < a);
+ BOOST_CHECK(a != b);
+ BOOST_CHECK(c < a);
+ BOOST_CHECK(a != c);
+
+ b++;
+ BOOST_CHECK(!(a > b));
+ BOOST_CHECK(!(b < a));
+ BOOST_CHECK(a == b);
+ BOOST_CHECK(c < b);
+ BOOST_CHECK(b != c);
+}
+
+QPID_AUTO_TEST_CASE(testIncrementPrefix)
+{
+ SequenceNumber a;
+ SequenceNumber b;
+ BOOST_CHECK(!(a > b));
+ BOOST_CHECK(!(b < a));
+ BOOST_CHECK(a == b);
+
+ SequenceNumber c = ++a;
+ BOOST_CHECK(a > b);
+ BOOST_CHECK(b < a);
+ BOOST_CHECK(a != b);
+ BOOST_CHECK(a == c);
+
+ ++b;
+ BOOST_CHECK(!(a > b));
+ BOOST_CHECK(!(b < a));
+ BOOST_CHECK(a == b);
+}
+
+QPID_AUTO_TEST_CASE(testWrapAround)
+{
+ const uint32_t max = 0xFFFFFFFF;
+ SequenceNumber a(max - 10);
+ SequenceNumber b(max - 5);
+ checkComparison(a, b, 5);
+
+ const uint32_t max_signed = 0x7FFFFFFF;
+ SequenceNumber c(max_signed - 10);
+ SequenceNumber d(max_signed - 5);
+ checkComparison(c, d, 5);
+}
+
+QPID_AUTO_TEST_CASE(testCondense)
+{
+ SequenceNumberSet set;
+ for (uint i = 0; i < 6; i++) {
+ set.push_back(SequenceNumber(i));
+ }
+ set.push_back(SequenceNumber(7));
+ for (uint i = 9; i < 13; i++) {
+ set.push_back(SequenceNumber(i));
+ }
+ set.push_back(SequenceNumber(13));
+ SequenceNumberSet actual = set.condense();
+
+ SequenceNumberSet expected;
+ expected.addRange(SequenceNumber(0), SequenceNumber(5));
+ expected.addRange(SequenceNumber(7), SequenceNumber(7));
+ expected.addRange(SequenceNumber(9), SequenceNumber(13));
+ BOOST_CHECK_EQUAL(expected, actual);
+}
+
+QPID_AUTO_TEST_CASE(testCondenseSingleRange)
+{
+ SequenceNumberSet set;
+ for (uint i = 0; i < 6; i++) {
+ set.push_back(SequenceNumber(i));
+ }
+ SequenceNumberSet actual = set.condense();
+
+ SequenceNumberSet expected;
+ expected.addRange(SequenceNumber(0), SequenceNumber(5));
+ BOOST_CHECK_EQUAL(expected, actual);
+}
+
+QPID_AUTO_TEST_CASE(testCondenseSingleItem)
+{
+ SequenceNumberSet set;
+ set.push_back(SequenceNumber(1));
+ SequenceNumberSet actual = set.condense();
+
+ SequenceNumberSet expected;
+ expected.addRange(SequenceNumber(1), SequenceNumber(1));
+ BOOST_CHECK_EQUAL(expected, actual);
+}
+
+QPID_AUTO_TEST_CASE(testDifference)
+{
+ SequenceNumber a;
+ SequenceNumber b;
+
+ for (int i = 0; i < 10; i++, ++a) {
+ BOOST_CHECK_EQUAL(i, a - b);
+ BOOST_CHECK_EQUAL(-i, b - a);
+ }
+
+ b = a;
+
+ for (int i = 0; i < 10; i++, ++b) {
+ BOOST_CHECK_EQUAL(-i, a - b);
+ BOOST_CHECK_EQUAL(i, b - a);
+ }
+}
+
+QPID_AUTO_TEST_CASE(testDifferenceWithWrapAround1)
+{
+ const uint32_t max = 0xFFFFFFFF;
+ SequenceNumber a(max - 5);
+ SequenceNumber b(max - 10);
+ checkDifference(a, b, 5);
+}
+
+QPID_AUTO_TEST_CASE(testDifferenceWithWrapAround2)
+{
+ const uint32_t max_signed = 0x7FFFFFFF;
+ SequenceNumber c(max_signed - 5);
+ SequenceNumber d(max_signed - 10);
+ checkDifference(c, d, 5);
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/SequenceSet.cpp b/RC9/qpid/cpp/src/tests/SequenceSet.cpp
new file mode 100644
index 0000000000..ba2f1391a1
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/SequenceSet.cpp
@@ -0,0 +1,140 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/framing/SequenceSet.h"
+#include "unit_test.h"
+#include <list>
+
+QPID_AUTO_TEST_SUITE(SequenceSetTestSuite)
+
+using namespace qpid::framing;
+
+struct RangeExpectations
+{
+ typedef std::pair<SequenceNumber, SequenceNumber> Range;
+ typedef std::list<Range> Ranges;
+
+ Ranges ranges;
+
+ RangeExpectations& expect(const SequenceNumber& start, const SequenceNumber& end) {
+ ranges.push_back(Range(start, end));
+ return *this;
+ }
+
+ void operator()(const SequenceNumber& start, const SequenceNumber& end) {
+ BOOST_CHECK(!ranges.empty());
+ if (!ranges.empty()) {
+ BOOST_CHECK_EQUAL(start, ranges.front().first);
+ BOOST_CHECK_EQUAL(end, ranges.front().second);
+ ranges.pop_front();
+ }
+ }
+
+ void check(SequenceSet& set) {
+ set.for_each(*this);
+ BOOST_CHECK(ranges.empty());
+ }
+};
+
+QPID_AUTO_TEST_CASE(testAdd) {
+ SequenceSet s;
+ s.add(2);
+ s.add(8,8);
+ s.add(3,5);
+
+ for (uint32_t i = 0; i <= 1; i++)
+ BOOST_CHECK(!s.contains(i));
+
+ for (uint32_t i = 2; i <= 5; i++)
+ BOOST_CHECK(s.contains(i));
+
+ for (uint32_t i = 6; i <= 7; i++)
+ BOOST_CHECK(!s.contains(i));
+
+ BOOST_CHECK(s.contains(8));
+
+ for (uint32_t i = 9; i <= 10; i++)
+ BOOST_CHECK(!s.contains(i));
+
+ RangeExpectations().expect(2, 5).expect(8, 8).check(s);
+
+ SequenceSet t;
+ t.add(6, 10);
+ t.add(s);
+
+ for (uint32_t i = 0; i <= 1; i++)
+ BOOST_CHECK(!t.contains(i));
+
+ for (uint32_t i = 2; i <= 10; i++)
+ BOOST_CHECK_MESSAGE(t.contains(i), t << " contains " << i);
+
+ RangeExpectations().expect(2, 10).check(t);
+}
+
+QPID_AUTO_TEST_CASE(testAdd2) {
+ SequenceSet s;
+ s.add(7,6);
+ s.add(4,4);
+ s.add(3,10);
+ s.add(2);
+ RangeExpectations().expect(2, 10).check(s);
+}
+
+QPID_AUTO_TEST_CASE(testRemove) {
+ SequenceSet s;
+ SequenceSet t;
+ s.add(0, 10);
+ t.add(0, 10);
+
+ s.remove(7);
+ s.remove(3, 5);
+ s.remove(9, 10);
+
+ t.remove(s);
+
+ for (uint32_t i = 0; i <= 2; i++) {
+ BOOST_CHECK(s.contains(i));
+ BOOST_CHECK(!t.contains(i));
+ }
+
+ for (uint32_t i = 3; i <= 5; i++) {
+ BOOST_CHECK(!s.contains(i));
+ BOOST_CHECK(t.contains(i));
+ }
+
+ BOOST_CHECK(s.contains(6));
+ BOOST_CHECK(!t.contains(6));
+
+ BOOST_CHECK(!s.contains(7));
+ BOOST_CHECK(t.contains(7));
+
+ BOOST_CHECK(s.contains(8));
+ BOOST_CHECK(!t.contains(8));
+
+ for (uint32_t i = 9; i <= 10; i++) {
+ BOOST_CHECK(!s.contains(i));
+ BOOST_CHECK(t.contains(i));
+ }
+
+ RangeExpectations().expect(0, 2).expect(6, 6).expect(8, 8).check(s);
+ RangeExpectations().expect(3, 5).expect(7, 7).expect(9, 10).check(t);
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+
diff --git a/RC9/qpid/cpp/src/tests/SessionState.cpp b/RC9/qpid/cpp/src/tests/SessionState.cpp
new file mode 100644
index 0000000000..2db25f9fe8
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/SessionState.cpp
@@ -0,0 +1,300 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "unit_test.h"
+
+#include "qpid/SessionState.h"
+#include "qpid/Exception.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/framing/SessionFlushBody.h"
+
+#include <boost/bind.hpp>
+#include <algorithm>
+#include <functional>
+#include <numeric>
+
+QPID_AUTO_TEST_SUITE(SessionStateTestSuite)
+
+using namespace std;
+using namespace boost;
+using namespace qpid::framing;
+
+// ================================================================
+// Utility functions.
+
+// Apply f to [begin, end) and accumulate the result
+template <class Iter, class T, class F>
+T applyAccumulate(Iter begin, Iter end, T seed, const F& f) {
+ return std::accumulate(begin, end, seed, bind(std::plus<T>(), _1, bind(f, _2)));
+}
+
+// Create a frame with a one-char string.
+AMQFrame& frame(char s) {
+ static AMQFrame frame;
+ frame.setBody(AMQContentBody(string(&s, 1)));
+ return frame;
+}
+
+// Simple string representation of a frame.
+string str(const AMQFrame& f) {
+ if (f.getMethod()) return "C"; // Command or Control
+ const AMQContentBody* c = dynamic_cast<const AMQContentBody*>(f.getBody());
+ if (c) return c->getData(); // Return data for content frames.
+ return "H"; // Must be a header.
+}
+// Make a string from a range of frames.
+string str(const boost::iterator_range<vector<AMQFrame>::const_iterator>& frames) {
+ string (*strFrame)(const AMQFrame&) = str;
+ return applyAccumulate(frames.begin(), frames.end(), string(), ptr_fun(strFrame));
+}
+// Make a transfer command frame.
+AMQFrame transferFrame(bool hasContent) {
+ AMQFrame t(in_place<MessageTransferBody>());
+ t.setFirstFrame(true);
+ t.setLastFrame(true);
+ t.setFirstSegment(true);
+ t.setLastSegment(!hasContent);
+ return t;
+}
+// Make a content frame
+AMQFrame contentFrame(string content, bool isLast=true) {
+ AMQFrame f(in_place<AMQContentBody>(content));
+ f.setFirstFrame(true);
+ f.setLastFrame(true);
+ f.setFirstSegment(false);
+ f.setLastSegment(isLast);
+ return f;
+}
+AMQFrame contentFrameChar(char content, bool isLast=true) {
+ return contentFrame(string(1, content), isLast);
+}
+
+// Send frame & return size of frame.
+size_t send(qpid::SessionState& s, const AMQFrame& f) { s.senderRecord(f); return f.encodedSize(); }
+// Send transfer command with no content.
+size_t transfer0(qpid::SessionState& s) { return send(s, transferFrame(false)); }
+// Send transfer frame with single content frame.
+size_t transfer1(qpid::SessionState& s, string content) {
+ return send(s,transferFrame(true)) + send(s,contentFrame(content));
+}
+size_t transfer1Char(qpid::SessionState& s, char content) {
+ return transfer1(s, string(1,content));
+}
+
+// Send transfer frame with multiple single-byte content frames.
+size_t transferN(qpid::SessionState& s, string content) {
+ size_t size=send(s, transferFrame(!content.empty()));
+ if (!content.empty()) {
+ char last = content[content.size()-1];
+ content.resize(content.size()-1);
+ size += applyAccumulate(content.begin(), content.end(), 0,
+ bind(&send, ref(s),
+ bind(contentFrameChar, _1, false)));
+ size += send(s, contentFrameChar(last, true));
+ }
+ return size;
+}
+
+// Send multiple transfers with single-byte content.
+size_t transfers(qpid::SessionState& s, string content) {
+ return applyAccumulate(content.begin(), content.end(), 0,
+ bind(transfer1Char, ref(s), _1));
+}
+
+size_t contentFrameSize(size_t n=1) { return AMQFrame(in_place<AMQContentBody>()).encodedSize() + n; }
+size_t transferFrameSize() { return AMQFrame(in_place<MessageTransferBody>()).encodedSize(); }
+
+// ==== qpid::SessionState test classes
+
+using qpid::SessionId;
+using qpid::SessionPoint;
+
+
+QPID_AUTO_TEST_CASE(testSendGetReplyList) {
+ qpid::SessionState s;
+ s.setTimeout(1);
+ s.senderGetCommandPoint();
+ transfer1(s, "abc");
+ transfers(s, "def");
+ transferN(s, "xyz");
+ BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(0,0))),"CabcCdCeCfCxyz");
+ // Ignore controls.
+ s.senderRecord(AMQFrame(in_place<SessionFlushBody>()));
+ BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(2,0))),"CeCfCxyz");
+}
+
+QPID_AUTO_TEST_CASE(testNeedFlush) {
+ qpid::SessionState::Configuration c;
+ // sync after 2 1-byte transfers or equivalent bytes.
+ c.replayFlushLimit = 2*(transferFrameSize()+contentFrameSize());
+ qpid::SessionState s(SessionId(), c);
+ s.setTimeout(1);
+ s.senderGetCommandPoint();
+ transfers(s, "a");
+ BOOST_CHECK(!s.senderNeedFlush());
+ transfers(s, "b");
+ BOOST_CHECK(s.senderNeedFlush());
+ s.senderRecordFlush();
+ BOOST_CHECK(!s.senderNeedFlush());
+ transfers(s, "c");
+ BOOST_CHECK(!s.senderNeedFlush());
+ transfers(s, "d");
+ BOOST_CHECK(s.senderNeedFlush());
+ BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint())), "CaCbCcCd");
+}
+
+QPID_AUTO_TEST_CASE(testPeerConfirmed) {
+ qpid::SessionState::Configuration c;
+ // sync after 2 1-byte transfers or equivalent bytes.
+ c.replayFlushLimit = 2*(transferFrameSize()+contentFrameSize());
+ qpid::SessionState s(SessionId(), c);
+ s.setTimeout(1);
+ s.senderGetCommandPoint();
+ transfers(s, "ab");
+ BOOST_CHECK(s.senderNeedFlush());
+ transfers(s, "cd");
+ BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(0,0))), "CaCbCcCd");
+ s.senderConfirmed(SessionPoint(3));
+ BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(3,0))), "Cd");
+ BOOST_CHECK(!s.senderNeedFlush());
+
+ // Multi-frame transfer.
+ transfer1(s, "efg");
+ transfers(s, "xy");
+ BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(3,0))), "CdCefgCxCy");
+ BOOST_CHECK(s.senderNeedFlush());
+
+ s.senderConfirmed(SessionPoint(4));
+ BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(4,0))), "CefgCxCy");
+ BOOST_CHECK(s.senderNeedFlush());
+
+ s.senderConfirmed(SessionPoint(5));
+ BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(5,0))), "CxCy");
+ BOOST_CHECK(s.senderNeedFlush());
+
+ s.senderConfirmed(SessionPoint(6));
+ BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(6,0))), "Cy");
+ BOOST_CHECK(!s.senderNeedFlush());
+}
+
+QPID_AUTO_TEST_CASE(testPeerCompleted) {
+ qpid::SessionState s;
+ s.setTimeout(1);
+ s.senderGetCommandPoint();
+ // Completion implies confirmation
+ transfers(s, "abc");
+ BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(0,0))), "CaCbCc");
+ SequenceSet set(SequenceSet() + 0 + 1);
+ s.senderCompleted(set);
+ BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(2,0))), "Cc");
+
+ transfers(s, "def");
+ // We dont do out-of-order confirmation, so this will only confirm up to 3:
+ set = SequenceSet(SequenceSet() + 2 + 3 + 5);
+ s.senderCompleted(set);
+ BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(4,0))), "CeCf");
+}
+
+QPID_AUTO_TEST_CASE(testReceive) {
+ // Advance expected/received correctly
+ qpid::SessionState s;
+ s.receiverSetCommandPoint(SessionPoint());
+ BOOST_CHECK_EQUAL(s.receiverGetExpected(), SessionPoint(0));
+ BOOST_CHECK_EQUAL(s.receiverGetReceived(), SessionPoint(0));
+
+ BOOST_CHECK(s.receiverRecord(transferFrame(false)));
+ BOOST_CHECK_EQUAL(s.receiverGetExpected(), SessionPoint(1));
+ BOOST_CHECK_EQUAL(s.receiverGetReceived(), SessionPoint(1));
+
+ BOOST_CHECK(s.receiverRecord(transferFrame(true)));
+ SessionPoint point = SessionPoint(1, transferFrameSize());
+ BOOST_CHECK_EQUAL(s.receiverGetExpected(), point);
+ BOOST_CHECK_EQUAL(s.receiverGetReceived(), point);
+ BOOST_CHECK(s.receiverRecord(contentFrame("", false)));
+ point.offset += contentFrameSize(0);
+ BOOST_CHECK_EQUAL(s.receiverGetExpected(), point);
+ BOOST_CHECK_EQUAL(s.receiverGetReceived(), point);
+ BOOST_CHECK(s.receiverRecord(contentFrame("", true)));
+ BOOST_CHECK_EQUAL(s.receiverGetExpected(), SessionPoint(2));
+ BOOST_CHECK_EQUAL(s.receiverGetReceived(), SessionPoint(2));
+
+ // Idempotence barrier, rewind expected & receive some duplicates.
+ s.receiverSetCommandPoint(SessionPoint(1));
+ BOOST_CHECK(!s.receiverRecord(transferFrame(false)));
+ BOOST_CHECK_EQUAL(s.receiverGetExpected(), SessionPoint(2));
+ BOOST_CHECK_EQUAL(s.receiverGetReceived(), SessionPoint(2));
+ BOOST_CHECK(s.receiverRecord(transferFrame(false)));
+ BOOST_CHECK_EQUAL(s.receiverGetExpected(), SessionPoint(3));
+ BOOST_CHECK_EQUAL(s.receiverGetReceived(), SessionPoint(3));
+}
+
+QPID_AUTO_TEST_CASE(testCompleted) {
+ // completed & unknownCompleted
+ qpid::SessionState s;
+ s.receiverSetCommandPoint(SessionPoint());
+ s.receiverRecord(transferFrame(false));
+ s.receiverRecord(transferFrame(false));
+ s.receiverRecord(transferFrame(false));
+ s.receiverCompleted(1);
+ BOOST_CHECK_EQUAL(s.receiverGetUnknownComplete(), SequenceSet(SequenceSet()+1));
+ s.receiverCompleted(0);
+ BOOST_CHECK_EQUAL(s.receiverGetUnknownComplete(),
+ SequenceSet(SequenceSet() + qpid::Range<SequenceNumber>(0,2)));
+ s.receiverKnownCompleted(SequenceSet(SequenceSet()+1));
+ BOOST_CHECK_EQUAL(s.receiverGetUnknownComplete(), SequenceSet(SequenceSet()+2));
+ // TODO aconway 2008-04-30: missing tests for known-completed.
+}
+
+QPID_AUTO_TEST_CASE(testNeedKnownCompleted) {
+ size_t flushInterval= 2*(transferFrameSize()+contentFrameSize())+1;
+ qpid::SessionState::Configuration c(flushInterval);
+ qpid::SessionState s(qpid::SessionId(), c);
+ s.senderGetCommandPoint();
+ transfers(s, "a");
+ SequenceSet set(SequenceSet() + 0);
+ s.senderCompleted(set);
+ BOOST_CHECK(!s.senderNeedKnownCompleted());
+
+ transfers(s, "b");
+ set += 1;
+ s.senderCompleted(set);
+ BOOST_CHECK(!s.senderNeedKnownCompleted());
+
+ transfers(s, "c");
+ set += 2;
+ s.senderCompleted(set);
+ BOOST_CHECK(s.senderNeedKnownCompleted());
+ s.senderRecordKnownCompleted();
+ BOOST_CHECK(!s.senderNeedKnownCompleted());
+
+ transfers(s, "de");
+ set += 3;
+ set += 4;
+ s.senderCompleted(set);
+ BOOST_CHECK(!s.senderNeedKnownCompleted());
+
+ transfers(s, "f");
+ set += 2;
+ s.senderCompleted(set);
+ BOOST_CHECK(s.senderNeedKnownCompleted());
+ s.senderRecordKnownCompleted();
+ BOOST_CHECK(!s.senderNeedKnownCompleted());
+}
+
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/Shlib.cpp b/RC9/qpid/cpp/src/tests/Shlib.cpp
new file mode 100644
index 0000000000..426a052c9f
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/Shlib.cpp
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "test_tools.h"
+#include "qpid/sys/Shlib.h"
+#include "qpid/Exception.h"
+
+#include "unit_test.h"
+
+QPID_AUTO_TEST_SUITE(ShlibTestSuite)
+
+using namespace qpid::sys;
+typedef void (*CallMe)(int*);
+
+QPID_AUTO_TEST_CASE(testShlib) {
+ Shlib sh(".libs/libshlibtest.so");
+ // Double cast to avoid ISO warning.
+ CallMe callMe=sh.getSymbol<CallMe>("callMe");
+ BOOST_REQUIRE(callMe != 0);
+ int unloaded=0;
+ callMe(&unloaded);
+ sh.unload();
+ BOOST_CHECK_EQUAL(42, unloaded);
+ try {
+ sh.getSymbol("callMe");
+ BOOST_FAIL("Expected exception");
+ }
+ catch (const qpid::Exception&) {}
+}
+
+QPID_AUTO_TEST_CASE(testAutoShlib) {
+ int unloaded = 0;
+ {
+ AutoShlib sh(".libs/libshlibtest.so");
+ CallMe callMe=sh.getSymbol<CallMe>("callMe");
+ BOOST_REQUIRE(callMe != 0);
+ callMe(&unloaded);
+ }
+ BOOST_CHECK_EQUAL(42, unloaded);
+}
+
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/SimpleTestCaseBase.cpp b/RC9/qpid/cpp/src/tests/SimpleTestCaseBase.cpp
new file mode 100644
index 0000000000..2739734731
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/SimpleTestCaseBase.cpp
@@ -0,0 +1,87 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "SimpleTestCaseBase.h"
+
+using namespace qpid;
+
+void SimpleTestCaseBase::start()
+{
+ if (worker.get()) {
+ worker->start();
+ }
+}
+
+void SimpleTestCaseBase::stop()
+{
+ if (worker.get()) {
+ worker->stop();
+ }
+}
+
+void SimpleTestCaseBase::report(client::Message& report)
+{
+ if (worker.get()) {
+ report.getHeaders().setInt("MESSAGE_COUNT", worker->getCount());
+ //add number of messages sent or received
+ std::stringstream reportstr;
+ reportstr << worker->getCount();
+ report.setData(reportstr.str());
+ }
+}
+
+SimpleTestCaseBase::Sender::Sender(ConnectionOptions& options,
+ const Exchange& _exchange,
+ const std::string& _key,
+ const int _messages)
+ : Worker(options, _messages), exchange(_exchange), key(_key) {}
+
+void SimpleTestCaseBase::Sender::init()
+{
+ channel.start();
+}
+
+void SimpleTestCaseBase::Sender::start(){
+ Message msg;
+ while (count < messages) {
+ channel.publish(msg, exchange, key);
+ count++;
+ }
+ stop();
+}
+
+SimpleTestCaseBase::Worker::Worker(ConnectionOptions& options, const int _messages) :
+ messages(_messages), count(0)
+{
+ connection.open(options.host, options.port);
+ connection.openChannel(channel);
+}
+
+void SimpleTestCaseBase::Worker::stop()
+{
+ channel.close();
+ connection.close();
+}
+
+int SimpleTestCaseBase::Worker::getCount()
+{
+ return count;
+}
+
diff --git a/RC9/qpid/cpp/src/tests/SimpleTestCaseBase.h b/RC9/qpid/cpp/src/tests/SimpleTestCaseBase.h
new file mode 100644
index 0000000000..0c1052d0c2
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/SimpleTestCaseBase.h
@@ -0,0 +1,89 @@
+#ifndef _SimpleTestCaseBase_
+#define _SimpleTestCaseBase_
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <memory>
+#include <sstream>
+
+#include "qpid/Exception.h"
+#include "qpid/client/Channel.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/Connection.h"
+#include "ConnectionOptions.h"
+#include "qpid/client/MessageListener.h"
+#include "TestCase.h"
+
+
+namespace qpid {
+
+using namespace qpid::client;
+
+class SimpleTestCaseBase : public TestCase
+{
+protected:
+ class Worker
+ {
+ protected:
+ client::Connection connection;
+ client::Channel channel;
+ const int messages;
+ int count;
+
+ public:
+
+ Worker(ConnectionOptions& options, const int messages);
+ virtual ~Worker(){}
+
+ virtual void stop();
+ virtual int getCount();
+ virtual void init() = 0;
+ virtual void start() = 0;
+ };
+
+ class Sender : public Worker
+ {
+ const Exchange& exchange;
+ const std::string key;
+ public:
+ Sender(ConnectionOptions& options,
+ const Exchange& exchange,
+ const std::string& key,
+ const int messages);
+ void init();
+ void start();
+ };
+
+ std::auto_ptr<Worker> worker;
+
+public:
+ virtual void assign(const std::string& role, framing::FieldTable& params, ConnectionOptions& options) = 0;
+
+ virtual ~SimpleTestCaseBase() {}
+
+ void start();
+ void stop();
+ void report(client::Message& report);
+};
+
+}
+
+#endif
diff --git a/RC9/qpid/cpp/src/tests/SocketProxy.h b/RC9/qpid/cpp/src/tests/SocketProxy.h
new file mode 100644
index 0000000000..9722359d82
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/SocketProxy.h
@@ -0,0 +1,143 @@
+#ifndef SOCKETPROXY_H
+#define SOCKETPROXY_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Socket.h"
+#include "qpid/sys/Poller.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/sys/Thread.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/client/Connection.h"
+#include "qpid/log/Statement.h"
+
+#include <algorithm>
+
+/**
+ * A simple socket proxy that forwards to another socket.
+ * Used between client & local broker to simulate network failures.
+ */
+class SocketProxy : private qpid::sys::Runnable
+{
+ public:
+ /** Connect to connectPort on host, start a forwarding thread.
+ * Listen for connection on getPort().
+ */
+ SocketProxy(int connectPort, const std::string host="localhost")
+ : closed(false), port(listener.listen()), dropClient(), dropServer()
+ {
+ client.connect(host, connectPort);
+ thread = qpid::sys::Thread(static_cast<qpid::sys::Runnable*>(this));
+ }
+
+ ~SocketProxy() { close(); }
+
+ /** Simulate a network disconnect. */
+ void close() {
+ {
+ qpid::sys::Mutex::ScopedLock l(lock);
+ if (closed) return;
+ closed=true;
+ }
+ poller.shutdown();
+ if (thread.id() != qpid::sys::Thread::current().id())
+ thread.join();
+ client.close();
+ }
+
+ /** Simulate lost packets, drop data from client */
+ void dropClientData(bool drop=true) { dropClient=drop; }
+
+ /** Simulate lost packets, drop data from server */
+ void dropServerData(bool drop=true) { dropServer=drop; }
+
+ bool isClosed() const {
+ qpid::sys::Mutex::ScopedLock l(lock);
+ return closed;
+ }
+
+ uint16_t getPort() const { return port; }
+
+ private:
+ static void throwErrno(const std::string& msg) {
+ throw qpid::Exception(msg+":"+qpid::sys::strError(errno));
+ }
+ static void throwIf(bool condition, const std::string& msg) {
+ if (condition) throw qpid::Exception(msg);
+ }
+
+ void run() {
+ std::auto_ptr<qpid::sys::Socket> server;
+ try {
+ qpid::sys::PollerHandle listenerHandle(listener);
+ poller.addFd(listenerHandle, qpid::sys::Poller::INPUT);
+ qpid::sys::Poller::Event event = poller.wait();
+ throwIf(event.type == qpid::sys::Poller::SHUTDOWN, "SocketProxy: Closed by close()");
+ throwIf(!(event.type == qpid::sys::Poller::READABLE && event.handle == &listenerHandle), "SocketProxy: Accept failed");
+
+ poller.delFd(listenerHandle);
+ server.reset(listener.accept(0, 0));
+
+ // Pump data between client & server sockets
+ qpid::sys::PollerHandle clientHandle(client);
+ qpid::sys::PollerHandle serverHandle(*server);
+ poller.addFd(clientHandle, qpid::sys::Poller::INPUT);
+ poller.addFd(serverHandle, qpid::sys::Poller::INPUT);
+ char buffer[1024];
+ for (;;) {
+ qpid::sys::Poller::Event event = poller.wait();
+ throwIf(event.type == qpid::sys::Poller::SHUTDOWN, "SocketProxy: Closed by close()");
+ throwIf(event.type == qpid::sys::Poller::DISCONNECTED, "SocketProxy: client/server disconnected");
+ if (event.handle == &serverHandle) {
+ ssize_t n = server->read(buffer, sizeof(buffer));
+ if (!dropServer) client.write(buffer, n);
+ poller.rearmFd(serverHandle);
+ } else if (event.handle == &clientHandle) {
+ ssize_t n = client.read(buffer, sizeof(buffer));
+ if (!dropClient) server->write(buffer, n);
+ poller.rearmFd(clientHandle);
+ } else {
+ throwIf(true, "SocketProxy: No handle ready");
+ }
+ }
+ }
+ catch (const std::exception& e) {
+ QPID_LOG(debug, "SocketProxy::run exception: " << e.what());
+ }
+ try {
+ if (server.get()) server->close();
+ close();
+ }
+ catch (const std::exception& e) {
+ QPID_LOG(debug, "SocketProxy::run exception in client/server close()" << e.what());
+ }
+ }
+
+ mutable qpid::sys::Mutex lock;
+ bool closed;
+ qpid::sys::Poller poller;
+ qpid::sys::Socket client, listener;
+ uint16_t port;
+ qpid::sys::Thread thread;
+ bool dropClient, dropServer;
+};
+
+#endif
diff --git a/RC9/qpid/cpp/src/tests/StringUtils.cpp b/RC9/qpid/cpp/src/tests/StringUtils.cpp
new file mode 100644
index 0000000000..6a19119288
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/StringUtils.cpp
@@ -0,0 +1,77 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <iostream>
+#include "qpid/StringUtils.h"
+
+#include "unit_test.h"
+
+QPID_AUTO_TEST_SUITE(StringUtilsTestSuite)
+
+using namespace qpid;
+using std::string;
+
+QPID_AUTO_TEST_CASE(testSplit_general)
+{
+ std::vector<std::string> results = split("a bbbb, car,d123,,,e", ", ");
+ BOOST_CHECK_EQUAL(5u, results.size());
+ BOOST_CHECK_EQUAL(string("a"), results[0]);
+ BOOST_CHECK_EQUAL(string("bbbb"), results[1]);
+ BOOST_CHECK_EQUAL(string("car"), results[2]);
+ BOOST_CHECK_EQUAL(string("d123"), results[3]);
+ BOOST_CHECK_EQUAL(string("e"), results[4]);
+}
+
+QPID_AUTO_TEST_CASE(testSplit_noDelims)
+{
+ std::vector<std::string> results = split("abc", ", ");
+ BOOST_CHECK_EQUAL(1u, results.size());
+ BOOST_CHECK_EQUAL(string("abc"), results[0]);
+}
+
+QPID_AUTO_TEST_CASE(testSplit_delimAtEnd)
+{
+ std::vector<std::string> results = split("abc def,,", ", ");
+ BOOST_CHECK_EQUAL(2u, results.size());
+ BOOST_CHECK_EQUAL(string("abc"), results[0]);
+ BOOST_CHECK_EQUAL(string("def"), results[1]);
+}
+
+QPID_AUTO_TEST_CASE(testSplit_delimAtStart)
+{
+ std::vector<std::string> results = split(",,abc def", ", ");
+ BOOST_CHECK_EQUAL(2u, results.size());
+ BOOST_CHECK_EQUAL(string("abc"), results[0]);
+ BOOST_CHECK_EQUAL(string("def"), results[1]);
+}
+
+QPID_AUTO_TEST_CASE(testSplit_onlyDelims)
+{
+ std::vector<std::string> results = split(",, , ", ", ");
+ BOOST_CHECK_EQUAL(0u, results.size());
+}
+
+QPID_AUTO_TEST_CASE(testSplit_empty)
+{
+ std::vector<std::string> results = split("", ", ");
+ BOOST_CHECK_EQUAL(0u, results.size());
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/TestCase.h b/RC9/qpid/cpp/src/tests/TestCase.h
new file mode 100644
index 0000000000..ba3330c951
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/TestCase.h
@@ -0,0 +1,64 @@
+#ifndef _TestCase_
+#define _TestCase_
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "ConnectionOptions.h"
+#include "qpid/client/Message.h"
+
+
+namespace qpid {
+
+/**
+ * Interface to be implemented by test cases for use with the test
+ * runner.
+ */
+class TestCase
+{
+public:
+ /**
+ * Directs the test case to act in a particular role. Some roles
+ * may be 'activated' at this stage others may require an explicit
+ * start request.
+ */
+ virtual void assign(const std::string& role, framing::FieldTable& params, client::ConnectionOptions& options) = 0;
+ /**
+ * Each test will be started on its own thread, which should block
+ * until the test completes (this may or may not require an
+ * explicit stop() request).
+ */
+ virtual void start() = 0;
+ /**
+ * Requests that the test be stopped if still running.
+ */
+ virtual void stop() = 0;
+ /**
+ * Allows the test to fill in details on the final report
+ * message. Will be called only after start has returned.
+ */
+ virtual void report(client::Message& report) = 0;
+
+ virtual ~TestCase() {}
+};
+
+}
+
+#endif
diff --git a/RC9/qpid/cpp/src/tests/TestMessageStore.h b/RC9/qpid/cpp/src/tests/TestMessageStore.h
new file mode 100644
index 0000000000..be1ed57349
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/TestMessageStore.h
@@ -0,0 +1,58 @@
+#ifndef _tests_TestMessageStore_h
+#define _tests_TestMessageStore_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/broker/NullMessageStore.h"
+#include <vector>
+
+using namespace qpid;
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+typedef std::pair<string, boost::intrusive_ptr<PersistableMessage> > msg_queue_pair;
+
+class TestMessageStore : public NullMessageStore
+{
+ public:
+ std::vector<boost::intrusive_ptr<PersistableMessage> > dequeued;
+ std::vector<msg_queue_pair> enqueued;
+
+ void dequeue(TransactionContext*,
+ const boost::intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue& /*queue*/)
+ {
+ dequeued.push_back(msg);
+ }
+
+ void enqueue(TransactionContext*,
+ const boost::intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue& queue)
+ {
+ msg->enqueueComplete();
+ enqueued.push_back(msg_queue_pair(queue.getName(), msg));
+ }
+
+ TestMessageStore() : NullMessageStore() {}
+ ~TestMessageStore(){}
+};
+
+#endif
diff --git a/RC9/qpid/cpp/src/tests/TestOptions.h b/RC9/qpid/cpp/src/tests/TestOptions.h
new file mode 100644
index 0000000000..a400fe5ecb
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/TestOptions.h
@@ -0,0 +1,79 @@
+#ifndef _TestOptions_
+#define _TestOptions_
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/Options.h"
+#include "qpid/log/Options.h"
+#include "qpid/Url.h"
+#include "qpid/log/Logger.h"
+#include "qpid/client/Connection.h"
+#include "ConnectionOptions.h"
+
+#include <iostream>
+#include <exception>
+
+namespace qpid {
+
+struct TestOptions : public qpid::Options
+{
+ TestOptions(const std::string& helpText_=std::string(),
+ const std::string& argv0=std::string())
+ : Options("Test Options"), help(false), log(argv0), helpText(helpText_)
+ {
+ addOptions()
+ ("help", optValue(help), "print this usage statement");
+ add(con);
+ add(log);
+ }
+
+ /** As well as parsing, throw help message if requested. */
+ void parse(int argc, char** argv) {
+ try {
+ qpid::Options::parse(argc, argv);
+ } catch (const std::exception& e) {
+ std::ostringstream msg;
+ msg << *this << std::endl << std::endl << e.what() << std::endl;
+ throw qpid::Options::Exception(msg.str());
+ }
+ qpid::log::Logger::instance().configure(log);
+ if (help) {
+ std::ostringstream msg;
+ msg << *this << std::endl << std::endl << helpText << std::endl;
+ throw qpid::Options::Exception(msg.str());
+ }
+ }
+
+ /** Open a connection using option values */
+ void open(qpid::client::Connection& connection) {
+ connection.open(con);
+ }
+
+
+ bool help;
+ ConnectionOptions con;
+ qpid::log::Options log;
+ std::string helpText;
+};
+
+}
+
+#endif
diff --git a/RC9/qpid/cpp/src/tests/TimerTest.cpp b/RC9/qpid/cpp/src/tests/TimerTest.cpp
new file mode 100644
index 0000000000..50712ff79c
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/TimerTest.cpp
@@ -0,0 +1,120 @@
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/broker/Timer.h"
+#include "qpid/sys/Monitor.h"
+#include "unit_test.h"
+#include <math.h>
+#include <iostream>
+#include <memory>
+#include <boost/format.hpp>
+#include <boost/lexical_cast.hpp>
+
+using namespace qpid::broker;
+using namespace qpid::sys;
+using boost::intrusive_ptr;
+using boost::dynamic_pointer_cast;
+
+class Counter
+{
+ Mutex lock;
+ uint counter;
+ public:
+ Counter() : counter(0) {}
+ uint next()
+ {
+ Mutex::ScopedLock l(lock);
+ return ++counter;
+ }
+};
+
+class TestTask : public TimerTask
+{
+ const AbsTime start;
+ const Duration expected;
+ AbsTime end;
+ bool fired;
+ uint position;
+ Monitor monitor;
+ Counter& counter;
+
+ public:
+ TestTask(Duration timeout, Counter& _counter)
+ : TimerTask(timeout), start(now()), expected(timeout), end(start), fired(false), counter(_counter) {}
+
+ void fire()
+ {
+ Monitor::ScopedLock l(monitor);
+ fired = true;
+ position = counter.next();
+ end = now();
+ monitor.notify();
+ }
+
+ void check(uint expected_position, uint64_t tolerance = 500 * TIME_MSEC)
+ {
+ Monitor::ScopedLock l(monitor);
+ BOOST_CHECK(fired);
+ BOOST_CHECK_EQUAL(expected_position, position);
+ Duration actual(start, end);
+ uint64_t difference = abs(expected - actual);
+ std::string msg(boost::lexical_cast<std::string>(boost::format("tolerance = %1%, difference = %2%") % tolerance % difference));
+ BOOST_CHECK_MESSAGE(difference < tolerance, msg);
+ }
+
+ void wait(Duration d)
+ {
+ Monitor::ScopedLock l(monitor);
+ monitor.wait(AbsTime(now(), d));
+ }
+};
+
+class DummyRunner : public Runnable
+{
+ public:
+ void run() {}
+};
+
+QPID_AUTO_TEST_SUITE(TimerTestSuite)
+
+QPID_AUTO_TEST_CASE(testGeneral)
+{
+ Counter counter;
+ Timer timer;
+ intrusive_ptr<TestTask> task1(new TestTask(Duration(3 * TIME_SEC), counter));
+ intrusive_ptr<TestTask> task2(new TestTask(Duration(1 * TIME_SEC), counter));
+ intrusive_ptr<TestTask> task3(new TestTask(Duration(4 * TIME_SEC), counter));
+ intrusive_ptr<TestTask> task4(new TestTask(Duration(2 * TIME_SEC), counter));
+
+ timer.add(task1);
+ timer.add(task2);
+ timer.add(task3);
+ timer.add(task4);
+
+ dynamic_pointer_cast<TestTask>(task3)->wait(Duration(6 * TIME_SEC));
+
+ dynamic_pointer_cast<TestTask>(task1)->check(3);
+ dynamic_pointer_cast<TestTask>(task2)->check(1);
+ dynamic_pointer_cast<TestTask>(task3)->check(4);
+ dynamic_pointer_cast<TestTask>(task4)->check(2);
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/TopicExchangeTest.cpp b/RC9/qpid/cpp/src/tests/TopicExchangeTest.cpp
new file mode 100644
index 0000000000..af4263de34
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/TopicExchangeTest.cpp
@@ -0,0 +1,167 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include "qpid/broker/TopicExchange.h"
+#include "unit_test.h"
+#include "test_tools.h"
+
+using namespace qpid::broker;
+
+Tokens makeTokens(const char** begin, const char** end)
+{
+ Tokens t;
+ t.insert(t.end(), begin, end);
+ return t;
+}
+
+// Calculate size of an array.
+#define LEN(a) (sizeof(a)/sizeof(a[0]))
+
+// Convert array to token vector
+#define TOKENS(a) makeTokens(a, a + LEN(a))
+
+#define ASSERT_NORMALIZED(expect, pattern) \
+ BOOST_CHECK_EQUAL(Tokens(expect), static_cast<Tokens>(TopicPattern(pattern)))
+
+
+QPID_AUTO_TEST_SUITE(TopicExchangeTestSuite)
+
+QPID_AUTO_TEST_CASE(testTokens)
+{
+ Tokens tokens("hello.world");
+ const char* expect[] = {"hello", "world"};
+ BOOST_CHECK_EQUAL(TOKENS(expect), tokens);
+
+ tokens = "a.b.c";
+ const char* expect2[] = { "a", "b", "c" };
+ BOOST_CHECK_EQUAL(TOKENS(expect2), tokens);
+
+ tokens = "";
+ BOOST_CHECK(tokens.empty());
+
+ tokens = "x";
+ const char* expect3[] = { "x" };
+ BOOST_CHECK_EQUAL(TOKENS(expect3), tokens);
+
+ tokens = (".x");
+ const char* expect4[] = { "", "x" };
+ BOOST_CHECK_EQUAL(TOKENS(expect4), tokens);
+
+ tokens = ("x.");
+ const char* expect5[] = { "x", "" };
+ BOOST_CHECK_EQUAL(TOKENS(expect5), tokens);
+
+ tokens = (".");
+ const char* expect6[] = { "", "" };
+ BOOST_CHECK_EQUAL(TOKENS(expect6), tokens);
+
+ tokens = ("..");
+ const char* expect7[] = { "", "", "" };
+ BOOST_CHECK_EQUAL(TOKENS(expect7), tokens);
+}
+
+QPID_AUTO_TEST_CASE(testNormalize)
+{
+ BOOST_CHECK(TopicPattern("").empty());
+ ASSERT_NORMALIZED("a.b.c", "a.b.c");
+ ASSERT_NORMALIZED("a.*.c", "a.*.c");
+ ASSERT_NORMALIZED("#", "#");
+ ASSERT_NORMALIZED("#", "#.#.#.#");
+ ASSERT_NORMALIZED("*.*.*.#", "#.*.#.*.#.#.*");
+ ASSERT_NORMALIZED("a.*.*.*.#", "a.*.#.*.#.*.#");
+ ASSERT_NORMALIZED("a.*.*.*.#", "a.*.#.*.#.*");
+}
+
+QPID_AUTO_TEST_CASE(testPlain)
+{
+ TopicPattern p("ab.cd.e");
+ BOOST_CHECK(p.match("ab.cd.e"));
+ BOOST_CHECK(!p.match("abx.cd.e"));
+ BOOST_CHECK(!p.match("ab.cd"));
+ BOOST_CHECK(!p.match("ab.cd..e."));
+ BOOST_CHECK(!p.match("ab.cd.e."));
+ BOOST_CHECK(!p.match(".ab.cd.e"));
+
+ p = "";
+ BOOST_CHECK(p.match(""));
+
+ p = ".";
+ BOOST_CHECK(p.match("."));
+}
+
+
+QPID_AUTO_TEST_CASE(testStar)
+{
+ TopicPattern p("a.*.b");
+ BOOST_CHECK(p.match("a.xx.b"));
+ BOOST_CHECK(!p.match("a.b"));
+
+ p = "*.x";
+ BOOST_CHECK(p.match("y.x"));
+ BOOST_CHECK(p.match(".x"));
+ BOOST_CHECK(!p.match("x"));
+
+ p = "x.x.*";
+ BOOST_CHECK(p.match("x.x.y"));
+ BOOST_CHECK(p.match("x.x."));
+ BOOST_CHECK(!p.match("x.x"));
+ BOOST_CHECK(!p.match("q.x.y"));
+}
+
+QPID_AUTO_TEST_CASE(testHash)
+{
+ TopicPattern p("a.#.b");
+ BOOST_CHECK(p.match("a.b"));
+ BOOST_CHECK(p.match("a.x.b"));
+ BOOST_CHECK(p.match("a..x.y.zz.b"));
+ BOOST_CHECK(!p.match("a.b."));
+ BOOST_CHECK(!p.match("q.x.b"));
+
+ p = "a.#";
+ BOOST_CHECK(p.match("a"));
+ BOOST_CHECK(p.match("a.b"));
+ BOOST_CHECK(p.match("a.b.c"));
+
+ p = "#.a";
+ BOOST_CHECK(p.match("a"));
+ BOOST_CHECK(p.match("x.y.a"));
+}
+
+QPID_AUTO_TEST_CASE(testMixed)
+{
+ TopicPattern p("*.x.#.y");
+ BOOST_CHECK(p.match("a.x.y"));
+ BOOST_CHECK(p.match("a.x.p.qq.y"));
+ BOOST_CHECK(!p.match("a.a.x.y"));
+ BOOST_CHECK(!p.match("aa.x.b.c"));
+
+ p = "a.#.b.*";
+ BOOST_CHECK(p.match("a.b.x"));
+ BOOST_CHECK(p.match("a.x.x.x.b.x"));
+}
+
+QPID_AUTO_TEST_CASE(testCombo)
+{
+ TopicPattern p("*.#.#.*.*.#");
+ BOOST_CHECK(p.match("x.y.z"));
+ BOOST_CHECK(p.match("x.y.z.a.b.c"));
+ BOOST_CHECK(!p.match("x.y"));
+ BOOST_CHECK(!p.match("x"));
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/TxBufferTest.cpp b/RC9/qpid/cpp/src/tests/TxBufferTest.cpp
new file mode 100644
index 0000000000..3d6a12cacc
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/TxBufferTest.cpp
@@ -0,0 +1,176 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/broker/TxBuffer.h"
+#include "unit_test.h"
+#include <iostream>
+#include <vector>
+#include "TxMocks.h"
+
+using namespace qpid::broker;
+using boost::static_pointer_cast;
+
+QPID_AUTO_TEST_SUITE(TxBufferTestSuite)
+
+QPID_AUTO_TEST_CASE(testCommitLocal)
+{
+ MockTransactionalStore store;
+ store.expectBegin().expectCommit();
+
+ MockTxOp::shared_ptr opA(new MockTxOp());
+ opA->expectPrepare().expectCommit();
+ MockTxOp::shared_ptr opB(new MockTxOp());
+ opB->expectPrepare().expectPrepare().expectCommit().expectCommit();//opB enlisted twice to test relative order
+ MockTxOp::shared_ptr opC(new MockTxOp());
+ opC->expectPrepare().expectCommit();
+
+ TxBuffer buffer;
+ buffer.enlist(static_pointer_cast<TxOp>(opA));
+ buffer.enlist(static_pointer_cast<TxOp>(opB));
+ buffer.enlist(static_pointer_cast<TxOp>(opB));//opB enlisted twice
+ buffer.enlist(static_pointer_cast<TxOp>(opC));
+
+ BOOST_CHECK(buffer.commitLocal(&store));
+ store.check();
+ BOOST_CHECK(store.isCommitted());
+ opA->check();
+ opB->check();
+ opC->check();
+}
+
+QPID_AUTO_TEST_CASE(testFailOnCommitLocal)
+{
+ MockTransactionalStore store;
+ store.expectBegin().expectAbort();
+
+ MockTxOp::shared_ptr opA(new MockTxOp());
+ opA->expectPrepare().expectRollback();
+ MockTxOp::shared_ptr opB(new MockTxOp(true));
+ opB->expectPrepare().expectRollback();
+ MockTxOp::shared_ptr opC(new MockTxOp());//will never get prepare as b will fail
+ opC->expectRollback();
+
+ TxBuffer buffer;
+ buffer.enlist(static_pointer_cast<TxOp>(opA));
+ buffer.enlist(static_pointer_cast<TxOp>(opB));
+ buffer.enlist(static_pointer_cast<TxOp>(opC));
+
+ BOOST_CHECK(!buffer.commitLocal(&store));
+ BOOST_CHECK(store.isAborted());
+ store.check();
+ opA->check();
+ opB->check();
+ opC->check();
+}
+
+QPID_AUTO_TEST_CASE(testPrepare)
+{
+ MockTxOp::shared_ptr opA(new MockTxOp());
+ opA->expectPrepare();
+ MockTxOp::shared_ptr opB(new MockTxOp());
+ opB->expectPrepare();
+ MockTxOp::shared_ptr opC(new MockTxOp());
+ opC->expectPrepare();
+
+ TxBuffer buffer;
+ buffer.enlist(static_pointer_cast<TxOp>(opA));
+ buffer.enlist(static_pointer_cast<TxOp>(opB));
+ buffer.enlist(static_pointer_cast<TxOp>(opC));
+
+ BOOST_CHECK(buffer.prepare(0));
+ opA->check();
+ opB->check();
+ opC->check();
+}
+
+QPID_AUTO_TEST_CASE(testFailOnPrepare)
+{
+ MockTxOp::shared_ptr opA(new MockTxOp());
+ opA->expectPrepare();
+ MockTxOp::shared_ptr opB(new MockTxOp(true));
+ opB->expectPrepare();
+ MockTxOp::shared_ptr opC(new MockTxOp());//will never get prepare as b will fail
+
+ TxBuffer buffer;
+ buffer.enlist(static_pointer_cast<TxOp>(opA));
+ buffer.enlist(static_pointer_cast<TxOp>(opB));
+ buffer.enlist(static_pointer_cast<TxOp>(opC));
+
+ BOOST_CHECK(!buffer.prepare(0));
+ opA->check();
+ opB->check();
+ opC->check();
+}
+
+QPID_AUTO_TEST_CASE(testRollback)
+{
+ MockTxOp::shared_ptr opA(new MockTxOp());
+ opA->expectRollback();
+ MockTxOp::shared_ptr opB(new MockTxOp(true));
+ opB->expectRollback();
+ MockTxOp::shared_ptr opC(new MockTxOp());
+ opC->expectRollback();
+
+ TxBuffer buffer;
+ buffer.enlist(static_pointer_cast<TxOp>(opA));
+ buffer.enlist(static_pointer_cast<TxOp>(opB));
+ buffer.enlist(static_pointer_cast<TxOp>(opC));
+
+ buffer.rollback();
+ opA->check();
+ opB->check();
+ opC->check();
+}
+
+QPID_AUTO_TEST_CASE(testBufferIsClearedAfterRollback)
+{
+ MockTxOp::shared_ptr opA(new MockTxOp());
+ opA->expectRollback();
+ MockTxOp::shared_ptr opB(new MockTxOp());
+ opB->expectRollback();
+
+ TxBuffer buffer;
+ buffer.enlist(static_pointer_cast<TxOp>(opA));
+ buffer.enlist(static_pointer_cast<TxOp>(opB));
+
+ buffer.rollback();
+ buffer.commit();//second call should not reach ops
+ opA->check();
+ opB->check();
+}
+
+QPID_AUTO_TEST_CASE(testBufferIsClearedAfterCommit)
+{
+ MockTxOp::shared_ptr opA(new MockTxOp());
+ opA->expectCommit();
+ MockTxOp::shared_ptr opB(new MockTxOp());
+ opB->expectCommit();
+
+ TxBuffer buffer;
+ buffer.enlist(static_pointer_cast<TxOp>(opA));
+ buffer.enlist(static_pointer_cast<TxOp>(opB));
+
+ buffer.commit();
+ buffer.rollback();//second call should not reach ops
+ opA->check();
+ opB->check();
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/TxMocks.h b/RC9/qpid/cpp/src/tests/TxMocks.h
new file mode 100644
index 0000000000..fe103c5fe5
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/TxMocks.h
@@ -0,0 +1,229 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _tests_TxMocks_h
+#define _tests_TxMocks_h
+
+
+#include "qpid/Exception.h"
+#include "qpid/broker/TransactionalStore.h"
+#include "qpid/broker/TxOp.h"
+#include <iostream>
+#include <vector>
+
+using namespace qpid::broker;
+using boost::static_pointer_cast;
+using std::string;
+
+template <class T> void assertEqualVector(std::vector<T>& expected, std::vector<T>& actual){
+ unsigned int i = 0;
+ while(i < expected.size() && i < actual.size()){
+ BOOST_CHECK_EQUAL(expected[i], actual[i]);
+ i++;
+ }
+ if (i < expected.size()) {
+ throw qpid::Exception(QPID_MSG("Missing " << expected[i]));
+ } else if (i < actual.size()) {
+ throw qpid::Exception(QPID_MSG("Extra " << actual[i]));
+ }
+ BOOST_CHECK_EQUAL(expected.size(), actual.size());
+}
+
+class TxOpConstants{
+protected:
+ const string PREPARE;
+ const string COMMIT;
+ const string ROLLBACK;
+
+ TxOpConstants() : PREPARE("PREPARE"), COMMIT("COMMIT"), ROLLBACK("ROLLBACK") {}
+};
+
+class MockTxOp : public TxOp, public TxOpConstants{
+ std::vector<string> expected;
+ std::vector<string> actual;
+ bool failOnPrepare;
+ string debugName;
+public:
+ typedef boost::shared_ptr<MockTxOp> shared_ptr;
+
+ MockTxOp() : failOnPrepare(false) {}
+ MockTxOp(bool _failOnPrepare) : failOnPrepare(_failOnPrepare) {}
+
+ void setDebugName(string name){
+ debugName = name;
+ }
+
+ void printExpected(){
+ std::cout << std::endl << "MockTxOp[" << debugName << "] expects: ";
+ for (std::vector<string>::iterator i = expected.begin(); i < expected.end(); i++) {
+ if(i != expected.begin()) std::cout << ", ";
+ std::cout << *i;
+ }
+ std::cout << std::endl;
+ }
+
+ void printActual(){
+ std::cout << std::endl << "MockTxOp[" << debugName << "] actual: ";
+ for (std::vector<string>::iterator i = actual.begin(); i < actual.end(); i++) {
+ if(i != actual.begin()) std::cout << ", ";
+ std::cout << *i;
+ }
+ std::cout << std::endl;
+ }
+
+ bool prepare(TransactionContext*) throw(){
+ actual.push_back(PREPARE);
+ return !failOnPrepare;
+ }
+ void commit() throw(){
+ actual.push_back(COMMIT);
+ }
+ void rollback() throw(){
+ if(!debugName.empty()) std::cout << std::endl << "MockTxOp[" << debugName << "]::rollback()" << std::endl;
+ actual.push_back(ROLLBACK);
+ }
+ MockTxOp& expectPrepare(){
+ expected.push_back(PREPARE);
+ return *this;
+ }
+ MockTxOp& expectCommit(){
+ expected.push_back(COMMIT);
+ return *this;
+ }
+ MockTxOp& expectRollback(){
+ expected.push_back(ROLLBACK);
+ return *this;
+ }
+ void check(){
+ assertEqualVector(expected, actual);
+ }
+
+ void accept(TxOpConstVisitor&) const {}
+
+ ~MockTxOp(){}
+};
+
+class MockTransactionalStore : public TransactionalStore{
+ const string BEGIN;
+ const string BEGIN2PC;
+ const string PREPARE;
+ const string COMMIT;
+ const string ABORT;
+ std::vector<string> expected;
+ std::vector<string> actual;
+
+ enum states {OPEN = 1, PREPARED = 2, COMMITTED = 3, ABORTED = 4};
+ int state;
+
+ class TestTransactionContext : public TPCTransactionContext{
+ MockTransactionalStore* store;
+ public:
+ TestTransactionContext(MockTransactionalStore* _store) : store(_store) {}
+ void prepare(){
+ if(!store->isOpen()) throw "txn already completed";
+ store->state = PREPARED;
+ }
+
+ void commit(){
+ if(!store->isOpen() && !store->isPrepared()) throw "txn already completed";
+ store->state = COMMITTED;
+ }
+
+ void abort(){
+ if(!store->isOpen() && !store->isPrepared()) throw "txn already completed";
+ store->state = ABORTED;
+ }
+ ~TestTransactionContext(){}
+ };
+
+public:
+ MockTransactionalStore() :
+ BEGIN("BEGIN"), BEGIN2PC("BEGIN2PC"), PREPARE("PREPARE"), COMMIT("COMMIT"), ABORT("ABORT"), state(OPEN){}
+
+ void collectPreparedXids(std::set<std::string>&)
+ {
+ throw "Operation not supported";
+ }
+
+ std::auto_ptr<TPCTransactionContext> begin(const std::string&){
+ actual.push_back(BEGIN2PC);
+ std::auto_ptr<TPCTransactionContext> txn(new TestTransactionContext(this));
+ return txn;
+ }
+ std::auto_ptr<TransactionContext> begin(){
+ actual.push_back(BEGIN);
+ std::auto_ptr<TransactionContext> txn(new TestTransactionContext(this));
+ return txn;
+ }
+ void prepare(TPCTransactionContext& ctxt){
+ actual.push_back(PREPARE);
+ dynamic_cast<TestTransactionContext&>(ctxt).prepare();
+ }
+ void commit(TransactionContext& ctxt){
+ actual.push_back(COMMIT);
+ dynamic_cast<TestTransactionContext&>(ctxt).commit();
+ }
+ void abort(TransactionContext& ctxt){
+ actual.push_back(ABORT);
+ dynamic_cast<TestTransactionContext&>(ctxt).abort();
+ }
+ MockTransactionalStore& expectBegin(){
+ expected.push_back(BEGIN);
+ return *this;
+ }
+ MockTransactionalStore& expectBegin2PC(){
+ expected.push_back(BEGIN2PC);
+ return *this;
+ }
+ MockTransactionalStore& expectPrepare(){
+ expected.push_back(PREPARE);
+ return *this;
+ }
+ MockTransactionalStore& expectCommit(){
+ expected.push_back(COMMIT);
+ return *this;
+ }
+ MockTransactionalStore& expectAbort(){
+ expected.push_back(ABORT);
+ return *this;
+ }
+ void check(){
+ assertEqualVector(expected, actual);
+ }
+
+ bool isPrepared(){
+ return state == PREPARED;
+ }
+
+ bool isCommitted(){
+ return state == COMMITTED;
+ }
+
+ bool isAborted(){
+ return state == ABORTED;
+ }
+
+ bool isOpen() const{
+ return state == OPEN;
+ }
+ ~MockTransactionalStore(){}
+};
+
+#endif
diff --git a/RC9/qpid/cpp/src/tests/TxPublishTest.cpp b/RC9/qpid/cpp/src/tests/TxPublishTest.cpp
new file mode 100644
index 0000000000..9e9715c987
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/TxPublishTest.cpp
@@ -0,0 +1,94 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/broker/NullMessageStore.h"
+#include "qpid/broker/RecoveryManager.h"
+#include "qpid/broker/TxPublish.h"
+#include "unit_test.h"
+#include <iostream>
+#include <list>
+#include <vector>
+#include "MessageUtils.h"
+#include "TestMessageStore.h"
+
+using std::list;
+using std::pair;
+using std::vector;
+using boost::intrusive_ptr;
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+struct TxPublishTest
+{
+
+ TestMessageStore store;
+ Queue::shared_ptr queue1;
+ Queue::shared_ptr queue2;
+ intrusive_ptr<Message> msg;
+ TxPublish op;
+
+ TxPublishTest() :
+ queue1(new Queue("queue1", false, &store, 0)),
+ queue2(new Queue("queue2", false, &store, 0)),
+ msg(MessageUtils::createMessage("exchange", "routing_key", "id")),
+ op(msg)
+ {
+ msg->getProperties<DeliveryProperties>()->setDeliveryMode(PERSISTENT);
+ op.deliverTo(queue1);
+ op.deliverTo(queue2);
+ }
+};
+
+
+QPID_AUTO_TEST_SUITE(TxPublishTestSuite)
+
+QPID_AUTO_TEST_CASE(testPrepare)
+{
+ TxPublishTest t;
+
+ intrusive_ptr<PersistableMessage> pmsg = static_pointer_cast<PersistableMessage>(t.msg);
+ //ensure messages are enqueued in store
+ t.op.prepare(0);
+ BOOST_CHECK_EQUAL((size_t) 2, t.store.enqueued.size());
+ BOOST_CHECK_EQUAL(string("queue1"), t.store.enqueued[0].first);
+ BOOST_CHECK_EQUAL(pmsg, t.store.enqueued[0].second);
+ BOOST_CHECK_EQUAL(string("queue2"), t.store.enqueued[1].first);
+ BOOST_CHECK_EQUAL(pmsg, t.store.enqueued[1].second);
+ BOOST_CHECK_EQUAL( true, ( static_pointer_cast<PersistableMessage>(t.msg))->isEnqueueComplete());
+}
+
+QPID_AUTO_TEST_CASE(testCommit)
+{
+ TxPublishTest t;
+
+ //ensure messages are delivered to queue
+ t.op.prepare(0);
+ t.op.commit();
+ BOOST_CHECK_EQUAL((uint32_t) 1, t.queue1->getMessageCount());
+ intrusive_ptr<Message> msg_dequeue = t.queue1->get().payload;
+
+ BOOST_CHECK_EQUAL( true, (static_pointer_cast<PersistableMessage>(msg_dequeue))->isEnqueueComplete());
+ BOOST_CHECK_EQUAL(t.msg, msg_dequeue);
+
+ BOOST_CHECK_EQUAL((uint32_t) 1, t.queue2->getMessageCount());
+ BOOST_CHECK_EQUAL(t.msg, t.queue2->get().payload);
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/Url.cpp b/RC9/qpid/cpp/src/tests/Url.cpp
new file mode 100644
index 0000000000..f3b42a7208
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/Url.cpp
@@ -0,0 +1,67 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+#include "unit_test.h"
+#include "test_tools.h"
+#include "qpid/Url.h"
+#include <boost/assign.hpp>
+
+using namespace std;
+using namespace qpid;
+using namespace boost::assign;
+
+QPID_AUTO_TEST_SUITE(UrlTestSuite)
+
+#define URL_CHECK_STR(STR) BOOST_CHECK_EQUAL(Url(STR).str(), STR)
+#define URL_CHECK_INVALID(STR) BOOST_CHECK_THROW(Url(STR), Url::Invalid)
+
+QPID_AUTO_TEST_CASE(TestParseTcp) {
+ URL_CHECK_STR("amqp:tcp:host:42");
+ URL_CHECK_STR("amqp:tcp:host-._~%ff%23:42"); // unreserved chars and pct encoded hex.
+
+ // Check defaults
+ BOOST_CHECK_EQUAL(Url("amqp:host:42").str(), "amqp:tcp:host:42");
+ BOOST_CHECK_EQUAL(Url("amqp:tcp:host").str(), "amqp:tcp:host:5672");
+ BOOST_CHECK_EQUAL(Url("amqp:tcp:").str(), "amqp:tcp:127.0.0.1:5672");
+ BOOST_CHECK_EQUAL(Url("amqp:").str(), "amqp:tcp:127.0.0.1:5672");
+ BOOST_CHECK_EQUAL(Url("amqp::42").str(), "amqp:tcp:127.0.0.1:42");
+
+ URL_CHECK_INVALID("amqp::badHost!#$#");
+ URL_CHECK_INVALID("amqp::host:badPort");
+}
+
+QPID_AUTO_TEST_CASE(TestParseExample) {
+ URL_CHECK_STR("amqp:example:x");
+ URL_CHECK_INVALID("amqp:example:badExample");
+}
+
+QPID_AUTO_TEST_CASE(TestParseMultiAddress) {
+ URL_CHECK_STR("amqp:tcp:host:0,example:y,tcp:foo:0,example:1");
+ URL_CHECK_STR("amqp:example:z,tcp:foo:0");
+ URL_CHECK_INVALID("amqp:tcp:h:0,");
+ URL_CHECK_INVALID(",amqp:tcp:h");
+}
+
+
+QPID_AUTO_TEST_CASE(TestInvalidAddress) {
+ URL_CHECK_INVALID("xxxx");
+ URL_CHECK_INVALID("");
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/Uuid.cpp b/RC9/qpid/cpp/src/tests/Uuid.cpp
new file mode 100644
index 0000000000..ee86d75a26
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/Uuid.cpp
@@ -0,0 +1,79 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/framing/Uuid.h"
+#include "qpid/framing/Buffer.h"
+
+#include "unit_test.h"
+
+#include <set>
+#include <alloca.h>
+
+QPID_AUTO_TEST_SUITE(UuidTestSuite)
+
+using namespace std;
+using namespace qpid::framing;
+
+struct UniqueSet : public std::set<Uuid> {
+ void operator()(const Uuid& uuid) {
+ BOOST_REQUIRE(find(uuid) == end());
+ insert(uuid);
+ }
+};
+
+QPID_AUTO_TEST_CASE(testUuidCtor) {
+ // Uniqueness
+ boost::array<Uuid,1000> uuids;
+ for_each(uuids.begin(), uuids.end(), mem_fun_ref(&Uuid::generate));
+ UniqueSet unique;
+ for_each(uuids.begin(), uuids.end(), unique);
+}
+
+boost::array<uint8_t, 16> sample = {{'\x1b', '\x4e', '\x28', '\xba', '\x2f', '\xa1', '\x11', '\xd2', '\x88', '\x3f', '\xb9', '\xa7', '\x61', '\xbd', '\xe3', '\xfb'}};
+const string sampleStr("1b4e28ba-2fa1-11d2-883f-b9a761bde3fb");
+
+QPID_AUTO_TEST_CASE(testUuidIstream) {
+ Uuid uuid;
+ istringstream in(sampleStr);
+ in >> uuid;
+ BOOST_CHECK(!in.fail());
+ BOOST_CHECK(uuid == sample);
+}
+
+QPID_AUTO_TEST_CASE(testUuidOstream) {
+ Uuid uuid(sample.c_array());
+ ostringstream out;
+ out << uuid;
+ BOOST_CHECK(out.good());
+ BOOST_CHECK_EQUAL(out.str(), sampleStr);
+}
+
+QPID_AUTO_TEST_CASE(testUuidEncodeDecode) {
+ char* buff = static_cast<char*>(::alloca(Uuid::size()));
+ Buffer wbuf(buff, Uuid::size());
+ Uuid uuid(sample.c_array());
+ uuid.encode(wbuf);
+
+ Buffer rbuf(buff, Uuid::size());
+ Uuid decoded;
+ decoded.decode(rbuf);
+ BOOST_CHECK_EQUAL(string(sample.begin(), sample.end()),
+ string(decoded.begin(), decoded.end()));
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/XmlClientSessionTest.cpp b/RC9/qpid/cpp/src/tests/XmlClientSessionTest.cpp
new file mode 100644
index 0000000000..98558f0a76
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/XmlClientSessionTest.cpp
@@ -0,0 +1,221 @@
+/*
+ *
+ * Licensed to the Apachef Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "unit_test.h"
+#include "test_tools.h"
+#include "BrokerFixture.h"
+#include "qpid/sys/Shlib.h"
+#include "qpid/sys/Monitor.h"
+#include "qpid/sys/Thread.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/framing/TransferContent.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/LocalQueue.h"
+#include "qpid/client/Session.h"
+#include "qpid/client/SubscriptionManager.h"
+
+#include <boost/optional.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include <vector>
+
+QPID_AUTO_TEST_SUITE(XmlClientSessionTest)
+
+using namespace qpid::client;
+
+using namespace qpid::client::arg;
+using namespace qpid::framing;
+using namespace qpid;
+using qpid::sys::Shlib;
+using qpid::sys::Monitor;
+using std::string;
+using std::cout;
+using std::endl;
+
+Shlib shlib("../.libs/xml.so");
+
+class SubscribedLocalQueue : public LocalQueue {
+ private:
+ SubscriptionManager& subscriptions;
+ public:
+ SubscribedLocalQueue(SubscriptionManager& subs) : subscriptions(subs) {}
+ Message get () { return pop(); }
+ virtual ~SubscribedLocalQueue() {}
+};
+
+
+struct SimpleListener : public MessageListener
+{
+ Monitor lock;
+ std::vector<Message> messages;
+
+ void received(Message& msg)
+ {
+ Monitor::ScopedLock l(lock);
+ messages.push_back(msg);
+ lock.notifyAll();
+ }
+
+ void waitFor(const uint n)
+ {
+ Monitor::ScopedLock l(lock);
+ while (messages.size() < n) {
+ lock.wait();
+ }
+ }
+};
+
+struct ClientSessionFixture : public ProxySessionFixture
+{
+ void declareSubscribe(const string& q="odd_blue",
+ const string& dest="xml")
+ {
+ session.queueDeclare(queue=q);
+ session.messageSubscribe(queue=q, destination=dest, acquireMode=1);
+ session.messageFlow(destination=dest, unit=0, value=0xFFFFFFFF);//messages
+ session.messageFlow(destination=dest, unit=1, value=0xFFFFFFFF);//bytes
+ }
+};
+
+// ########### START HERE ####################################
+
+
+
+QPID_AUTO_TEST_CASE(testXmlBinding) {
+ ClientSessionFixture f;
+
+ SubscriptionManager subscriptions(f.session);
+ SubscribedLocalQueue localQueue(subscriptions);
+
+ f.session.exchangeDeclare(qpid::client::arg::exchange="xml", qpid::client::arg::type="xml");
+ f.session.queueDeclare(qpid::client::arg::queue="odd_blue");
+ subscriptions.subscribe(localQueue, "odd_blue");
+
+ FieldTable binding;
+ binding.setString("xquery", "declare variable $color external;"
+ "(./message/id mod 2 = 1) and ($color = 'blue')");
+ f.session.exchangeBind(qpid::client::arg::exchange="xml", qpid::client::arg::queue="odd_blue", qpid::client::arg::bindingKey="query_name", qpid::client::arg::arguments=binding);
+
+ Message message;
+ message.getDeliveryProperties().setRoutingKey("query_name");
+
+ message.getHeaders().setString("color", "blue");
+ string m = "<message><id>1</id></message>";
+ message.setData(m);
+
+ f.session.messageTransfer(qpid::client::arg::content=message, qpid::client::arg::destination="xml");
+
+ Message m2 = localQueue.get();
+ BOOST_CHECK_EQUAL(m, m2.getData());
+}
+
+/**
+ * Ensure that multiple queues can be bound using the same routing key
+ */
+QPID_AUTO_TEST_CASE(testXMLBindMultipleQueues) {
+ ClientSessionFixture f;
+
+
+ f.session.exchangeDeclare(arg::exchange="xml", arg::type="xml");
+ f.session.queueDeclare(arg::queue="blue", arg::exclusive=true, arg::autoDelete=true);
+ f.session.queueDeclare(arg::queue="red", arg::exclusive=true, arg::autoDelete=true);
+
+ FieldTable blue;
+ blue.setString("xquery", "./colour = 'blue'");
+ f.session.exchangeBind(arg::exchange="xml", arg::queue="blue", arg::bindingKey="by-colour", arg::arguments=blue);
+ FieldTable red;
+ red.setString("xquery", "./colour = 'red'");
+ f.session.exchangeBind(arg::exchange="xml", arg::queue="red", arg::bindingKey="by-colour", arg::arguments=red);
+
+ Message sent1("<colour>blue</colour>", "by-colour");
+ f.session.messageTransfer(arg::content=sent1, arg::destination="xml");
+
+ Message sent2("<colour>red</colour>", "by-colour");
+ f.session.messageTransfer(arg::content=sent2, arg::destination="xml");
+
+ Message received;
+ BOOST_CHECK(f.subs.get(received, "blue"));
+ BOOST_CHECK_EQUAL(sent1.getData(), received.getData());
+ BOOST_CHECK(f.subs.get(received, "red"));
+ BOOST_CHECK_EQUAL(sent2.getData(), received.getData());
+}
+
+//### Test: Bad XML does not kill the server - and does not even
+// raise an exception, the content is not required to be XML.
+
+QPID_AUTO_TEST_CASE(testXMLSendBadXML) {
+ ClientSessionFixture f;
+
+ f.session.exchangeDeclare(arg::exchange="xml", arg::type="xml");
+ f.session.queueDeclare(arg::queue="blue", arg::exclusive=true, arg::autoDelete=true)\
+ ;
+ f.session.queueDeclare(arg::queue="red", arg::exclusive=true, arg::autoDelete=true);
+
+ FieldTable blue;
+ blue.setString("xquery", "./colour = 'blue'");
+ f.session.exchangeBind(arg::exchange="xml", arg::queue="blue", arg::bindingKey="by-c\
+olour", arg::arguments=blue);
+ FieldTable red;
+ red.setString("xquery", "./colour = 'red'");
+ f.session.exchangeBind(arg::exchange="xml", arg::queue="red", arg::bindingKey="by-co\
+lour", arg::arguments=red);
+
+ Message sent1("<>colour>blue</colour>", "by-colour");
+ f.session.messageTransfer(arg::content=sent1, arg::destination="xml");
+
+ BOOST_CHECK_EQUAL(1, 1);
+}
+
+
+//### Test: Bad XQuery does not kill the server, but does raise an exception
+
+QPID_AUTO_TEST_CASE(testXMLBadXQuery) {
+ ClientSessionFixture f;
+
+ f.session.exchangeDeclare(arg::exchange="xml", arg::type="xml");
+ f.session.queueDeclare(arg::queue="blue", arg::exclusive=true, arg::autoDelete=true)\
+ ;
+
+ try {
+ ScopedSuppressLogging sl; // Supress logging of error messages for expected error.
+ FieldTable blue;
+ blue.setString("xquery", "./colour $=! 'blue'");
+ f.session.exchangeBind(arg::exchange="xml", arg::queue="blue", arg::bindingKey="by-c\
+olour", arg::arguments=blue);
+ }
+ catch (const InternalErrorException& e) {
+ return;
+ }
+ BOOST_ERROR("A bad XQuery must raise an exception when used in an XML Binding.");
+
+}
+
+
+//### Test: Each session can provide its own definition for a query name
+
+
+
+//### Test: Bindings persist, surviving broker restart
+
+QPID_AUTO_TEST_SUITE_END()
+
diff --git a/RC9/qpid/cpp/src/tests/acl.py b/RC9/qpid/cpp/src/tests/acl.py
new file mode 100755
index 0000000000..671b2fe247
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/acl.py
@@ -0,0 +1,459 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import sys
+import qpid
+from qpid.util import connect
+from qpid.connection import Connection
+from qpid.datatypes import uuid4
+from qpid.testlib import TestBase010, testrunner
+from qmf.console import Session
+from qpid.datatypes import Message
+
+def scan_args(name, default=None, args=sys.argv[1:]):
+ if (name in args):
+ pos = args.index(name)
+ return args[pos + 1]
+ elif default:
+ return default
+ else:
+ print "Please specify extra argument: %s" % name
+ sys.exit(2)
+
+def extract_args(name, args):
+ if (name in args):
+ pos = args.index(name)
+ del args[pos:pos+2]
+ else:
+ return None
+
+def get_broker_port():
+ return scan_args("--port", "5672")
+
+def get_session(user, passwd):
+ socket = connect('127.0.0.1', int(get_broker_port()))
+ connection = Connection (sock=socket, username=user, password=passwd)
+ connection.start()
+ return connection.session(str(uuid4()))
+
+class ACLFile:
+ def __init__(self):
+ self.f = open('data_dir/policy.acl','w');
+
+ def write(self,line):
+ self.f.write(line)
+
+ def close(self):
+ self.f.close()
+
+class ACLTests(TestBase010):
+
+ def reload_acl(self):
+ acl = self.qmf.getObjects(_class="acl")[0]
+ return acl.reloadACLFile()
+
+ def setUp(self):
+ aclf = ACLFile()
+ aclf.write('acl allow all all\n')
+ aclf.close()
+ TestBase010.setUp(self)
+ self.startQmf()
+ self.reload_acl()
+
+ #=====================================
+ # ACL general tests
+ #=====================================
+
+ def test_deny_all(self):
+ """
+ Test the deny all mode
+ """
+ aclf = ACLFile()
+ aclf.write('acl allow guest@QPID all all\n')
+ aclf.write('acl allow bob@QPID create queue\n')
+ aclf.write('acl deny all all')
+ aclf.close()
+
+ self.reload_acl()
+
+ session = get_session('bob','bob')
+ try:
+ session.queue_declare(queue="deny_queue")
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue create request");
+ self.fail("Error during queue create request");
+
+ try:
+ session.exchange_bind(exchange="amq.direct", queue="deny_queue", binding_key="routing_key")
+ self.fail("ACL should deny queue bind request");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+
+ def test_allow_all(self):
+ """
+ Test the allow all mode
+ """
+ aclf = ACLFile()
+ aclf.write('acl deny bob@QPID bind exchange\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ self.reload_acl()
+
+ session = get_session('bob','bob')
+ try:
+ session.queue_declare(queue="allow_queue")
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue create request");
+ self.fail("Error during queue create request");
+
+ try:
+ session.exchange_bind(exchange="amq.direct", queue="allow_queue", binding_key="routing_key")
+ self.fail("ACL should deny queue bind request");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+
+
+ #=====================================
+ # ACL file format tests
+ #=====================================
+
+ def test_empty_groups(self):
+ """
+ Test empty groups
+ """
+ aclf = ACLFile()
+ aclf.write('acl group\n')
+ aclf.write('acl group admins bob@QPID joe@QPID\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result.text.find("Insufficient tokens for acl definition",0,len(result.text)) == -1):
+ self.fail("ACL Reader should reject the acl file due to empty group name")
+
+ def test_illegal_acl_formats(self):
+ """
+ Test illegal acl formats
+ """
+ aclf = ACLFile()
+ aclf.write('acl group admins bob@QPID joe@QPID\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result.text.find("Unknown ACL permission",0,len(result.text)) == -1):
+ self.fail(result)
+
+ def test_illegal_extension_lines(self):
+ """
+ Test illegal extension lines
+ """
+
+ aclf = ACLFile()
+ aclf.write('group admins bob@QPID \ ')
+ aclf.write(' \ \n')
+ aclf.write('joe@QPID \n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result.text.find("contains illegal characters",0,len(result.text)) == -1):
+ self.fail(result)
+
+
+
+ #=====================================
+ # ACL queue tests
+ #=====================================
+
+ def test_queue_acl(self):
+ """
+ Test various modes for queue acl
+ """
+ aclf = ACLFile()
+ aclf.write('acl deny bob@QPID create queue name=q1 durable=true passive=true\n')
+ aclf.write('acl deny bob@QPID create queue name=q2 exclusive=true\n')
+ aclf.write('acl deny bob@QPID access queue name=q3\n')
+ aclf.write('acl deny bob@QPID purge queue name=q3\n')
+ aclf.write('acl deny bob@QPID delete queue name=q4\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ self.reload_acl()
+
+ session = get_session('bob','bob')
+
+ try:
+ session.queue_declare(queue="q1", durable='true', passive='true')
+ self.fail("ACL should deny queue create request with name=q1 durable=true passive=true");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.queue_declare(queue="q2", exclusive='true')
+ self.fail("ACL should deny queue create request with name=q2 exclusive=true");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.queue_declare(queue="q3", exclusive='true')
+ session.queue_declare(queue="q4", durable='true')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue create request for q3 and q4 with any parameter");
+
+ try:
+ session.queue_query(queue="q3")
+ self.fail("ACL should deny queue query request for q3");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.queue_purge(queue="q3")
+ self.fail("ACL should deny queue purge request for q3");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.queue_purge(queue="q4")
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue purge request for q4");
+
+ try:
+ session.queue_delete(queue="q4")
+ self.fail("ACL should deny queue delete request for q4");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.queue_delete(queue="q3")
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue delete request for q3");
+
+ #=====================================
+ # ACL exchange tests
+ #=====================================
+
+ def test_exchange_acl(self):
+ """
+ Test various modes for exchange acl
+ """
+ aclf = ACLFile()
+ aclf.write('acl deny bob@QPID create exchange name=testEx durable=true passive=true\n')
+ aclf.write('acl deny bob@QPID create exchange name=ex1 type=direct\n')
+ aclf.write('acl deny bob@QPID access exchange name=myEx\n')
+ aclf.write('acl deny bob@QPID bind exchange name=myEx queuename=q1 routingkey=rk1\n')
+ aclf.write('acl deny bob@QPID unbind exchange name=myEx queuename=q1 routingkey=rk1\n')
+ aclf.write('acl deny bob@QPID delete exchange name=myEx\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ self.reload_acl()
+
+ session = get_session('bob','bob')
+
+ try:
+ session.exchange_declare(exchange='testEx', durable='true', passive='true')
+ self.fail("ACL should deny exchange create request with name=testEx durable=true passive=true");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.exchange_declare(exchange='ex1', type='direct')
+ self.fail("ACL should deny exchange create request with name=ex1 type=direct");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.exchange_declare(exchange='myXml', type='direct')
+ session.queue_declare(queue='q1')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange create request for myXml with any parameter");
+
+ try:
+ session.exchange_query(name='myEx')
+ self.fail("ACL should deny queue query request for q3");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.exchange_bind(exchange='myEx', queue='q1', binding_key='rk1')
+ self.fail("ACL should deny exchange bind request with exchange='myEx' queuename='q1' bindingkey='rk1'");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.exchange_bind(exchange='myXml', queue='q1', binding_key='x')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange bind request for exchange='myXml', queue='q1', binding_key='x'");
+ try:
+ session.exchange_unbind(exchange='myEx', queue='q1', binding_key='rk1')
+ self.fail("ACL should deny exchange unbind request with exchange='myEx' queuename='q1' bindingkey='rk1'");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.exchange_unbind(exchange='myXml', queue='q1', binding_key='x')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange unbind request for exchange='myXml', queue='q1', binding_key='x'");
+
+ try:
+ session.exchange_delete(exchange='myEx')
+ self.fail("ACL should deny exchange delete request for myEx");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.exchange_delete(exchange='myXml')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange delete request for myXml");
+
+
+ #=====================================
+ # ACL consume tests
+ #=====================================
+
+ def test_consume_acl(self):
+ """
+ Test various consume acl
+ """
+ aclf = ACLFile()
+ aclf.write('acl deny bob@QPID consume queue name=q1 durable=true\n')
+ aclf.write('acl deny bob@QPID consume queue name=q2 exclusive=true\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ self.reload_acl()
+
+ session = get_session('bob','bob')
+
+
+ try:
+ session.queue_declare(queue='q1', durable='true')
+ session.queue_declare(queue='q2', exclusive='true')
+ session.queue_declare(queue='q3', durable='true')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow create queue request");
+
+ try:
+ session.message_subscribe(queue='q1', destination='myq1')
+ self.fail("ACL should deny message subscriber request for queue='q1'");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.message_subscribe(queue='q2', destination='myq1')
+ self.fail("ACL should deny message subscriber request for queue='q2'");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.message_subscribe(queue='q3', destination='myq1')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow create message subscribe");
+
+
+ #=====================================
+ # ACL publish tests
+ #=====================================
+
+ def test_publish_acl(self):
+ """
+ Test various publish acl
+ """
+ aclf = ACLFile()
+ aclf.write('acl deny bob@QPID publish exchange name=amq.direct routingkey=rk1\n')
+ aclf.write('acl deny bob@QPID publish exchange name=amq.topic\n')
+ aclf.write('acl deny bob@QPID publish exchange name=myEx routingkey=rk2\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ self.reload_acl()
+
+ session = get_session('bob','bob')
+
+ try:
+ session.exchange_declare(exchange='myEx', type='topic')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange create request for myEx with any parameter");
+
+ props = session.delivery_properties(routing_key="rk1")
+
+ try:
+ session.message_transfer(destination="amq.direct", message=Message(props,"Test"))
+ self.fail("ACL should deny message transfer to name=amq.direct routingkey=rk1");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.message_transfer(destination="amq.topic", message=Message(props,"Test"))
+ self.fail("ACL should deny message transfer to name=amq.topic");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.message_transfer(destination="myEx", message=Message(props,"Test"))
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow message transfer to exchange myEx with routing key rk1");
+
+
+ props = session.delivery_properties(routing_key="rk2")
+ try:
+ session.message_transfer(destination="amq.direct", message=Message(props,"Test"))
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow message transfer to exchange amq.direct");
+
+
+if __name__ == '__main__':
+ args = sys.argv[1:]
+ #need to remove the extra options from args as test runner doesn't recognize them
+ extract_args("--port", args)
+ args.append("acl")
+
+ if not testrunner.run(args): sys.exit(1)
diff --git a/RC9/qpid/cpp/src/tests/ais_check b/RC9/qpid/cpp/src/tests/ais_check
new file mode 100755
index 0000000000..5687110165
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/ais_check
@@ -0,0 +1,56 @@
+#!/bin/sh
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+srcdir=`dirname $0`
+
+# Check AIS requirements and run tests if found.
+id -nG | grep '\<ais\>' >/dev/null || \
+ NOGROUP="You are not a member of the ais group."
+ps -u root | grep 'aisexec\|corosync' >/dev/null || \
+ NOAISEXEC="The aisexec or corosync daemon is not running as root"
+
+if test -n "$NOGROUP" -o -n "$NOAISEXEC"; then
+ cat <<EOF
+
+ =========== WARNING: NOT RUNNING AIS TESTS ==============
+
+ Tests that depend on the openais library (used for clustering)
+ will not be run because:
+
+ $NOGROUP
+ $NOAISEXEC
+
+ ==========================================================
+
+EOF
+ exit 0; # A warning, not a failure.
+fi
+
+# Execute command with the ais group set.
+with_ais_group() {
+ id -nG | grep '\<ais\>' >/dev/null || { echo "You are not a member of the ais group."; exit 1; }
+ echo $* | newgrp ais
+}
+
+# Run the tests
+srcdir=`dirname $0`
+with_ais_group $srcdir/run_test ./cluster_test || ERROR=1
+exit $ERROR
+
diff --git a/RC9/qpid/cpp/src/tests/ais_test.cpp b/RC9/qpid/cpp/src/tests/ais_test.cpp
new file mode 100644
index 0000000000..00c61242e4
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/ais_test.cpp
@@ -0,0 +1,23 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// Defines test_main function to link with actual unit test code.
+#define BOOST_AUTO_TEST_MAIN // Boost 1.33
+#define BOOST_TEST_MAIN
+#include "unit_test.h"
+
diff --git a/RC9/qpid/cpp/src/tests/allSegmentTypes.h b/RC9/qpid/cpp/src/tests/allSegmentTypes.h
new file mode 100644
index 0000000000..e942250c89
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/allSegmentTypes.h
@@ -0,0 +1,128 @@
+#ifndef TESTS_ALLSEGMENTTYPES_H
+#define TESTS_ALLSEGMENTTYPES_H
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+///
+/// This file was automatically generated from the AMQP specification.
+/// Do not edit.
+///
+
+
+#include "qpid/amqp_0_10/specification.h"
+#include "qpid/amqp_0_10/Header.h"
+#include "qpid/amqp_0_10/Body.h"
+
+using namespace qpid::amqp_0_10;
+
+template <class Op> size_t allSegmentTypes(Op& op) {
+ op(Header());
+ op(Body());
+ op(ControlHolder(connection::Start()));
+ op(ControlHolder(connection::StartOk()));
+ op(ControlHolder(connection::Secure()));
+ op(ControlHolder(connection::SecureOk()));
+ op(ControlHolder(connection::Tune()));
+ op(ControlHolder(connection::TuneOk()));
+ op(ControlHolder(connection::Open()));
+ op(ControlHolder(connection::OpenOk()));
+ // op(ControlHolder(connection::Redirect())); // known-hosts array
+ op(ControlHolder(connection::Heartbeat()));
+ // op(ControlHolder(connection::Close())); // class/method dropped
+ op(ControlHolder(connection::CloseOk()));
+ op(ControlHolder(session::Attach()));
+ op(ControlHolder(session::Attached()));
+ op(ControlHolder(session::Detach()));
+ op(ControlHolder(session::Detached()));
+ op(ControlHolder(session::RequestTimeout()));
+ op(ControlHolder(session::Timeout()));
+ op(ControlHolder(session::CommandPoint()));
+ // op(ControlHolder(session::Expected())); // fragments array encoding problem
+ // op(ControlHolder(session::Confirmed())); // fragments array encoding problem
+ op(ControlHolder(session::Completed()));
+ op(ControlHolder(session::KnownCompleted()));
+ op(ControlHolder(session::Flush()));
+ op(ControlHolder(session::Gap()));
+ // FIXME aconway 2008-04-15: command encoding, fix headers, fix sized structs.
+ op(CommandHolder(execution::Sync()));
+ op(CommandHolder(execution::Result()));
+
+ // FIXME aconway 2008-04-16: investigate remaining failures.
+ // op(CommandHolder(execution::Exception()));
+ op(CommandHolder(message::Transfer()));
+ op(CommandHolder(message::Accept()));
+ // op(CommandHolder(message::Reject()));
+ op(CommandHolder(message::Release()));
+ op(CommandHolder(message::Acquire()));
+ // op(CommandHolder(message::Resume()));
+ op(CommandHolder(message::Subscribe()));
+ op(CommandHolder(message::Cancel()));
+ op(CommandHolder(message::SetFlowMode()));
+ op(CommandHolder(message::Flow()));
+ op(CommandHolder(message::Flush()));
+ op(CommandHolder(message::Stop()));
+ op(CommandHolder(tx::Select()));
+ op(CommandHolder(tx::Commit()));
+ op(CommandHolder(tx::Rollback()));
+ op(CommandHolder(dtx::Select()));
+ // op(CommandHolder(dtx::Start()));
+ // op(CommandHolder(dtx::End()));
+ // op(CommandHolder(dtx::Commit()));
+ // op(CommandHolder(dtx::Forget()));
+ // op(CommandHolder(dtx::GetTimeout()));
+ // op(CommandHolder(dtx::Prepare()));
+ // op(CommandHolder(dtx::Recover()));
+ // op(CommandHolder(dtx::Rollback()));
+ // op(CommandHolder(dtx::SetTimeout()));
+ op(CommandHolder(exchange::Declare()));
+ op(CommandHolder(exchange::Delete()));
+ op(CommandHolder(exchange::Query()));
+ op(CommandHolder(exchange::Bind()));
+ op(CommandHolder(exchange::Unbind()));
+ op(CommandHolder(exchange::Bound()));
+ op(CommandHolder(queue::Declare()));
+ op(CommandHolder(queue::Delete()));
+ op(CommandHolder(queue::Purge()));
+ op(CommandHolder(queue::Query()));
+ // op(CommandHolder(file::Qos()));
+ // op(CommandHolder(file::QosOk()));
+// op(CommandHolder(file::Consume()));
+// op(CommandHolder(file::ConsumeOk()));
+// op(CommandHolder(file::Cancel()));
+// op(CommandHolder(file::Open()));
+// op(CommandHolder(file::OpenOk()));
+// op(CommandHolder(file::Stage()));
+// op(CommandHolder(file::Publish()));
+// op(CommandHolder(file::Return()));
+// op(CommandHolder(file::Deliver()));
+// op(CommandHolder(file::Ack()));
+// op(CommandHolder(file::Reject()));
+// op(CommandHolder(stream::Qos()));
+// op(CommandHolder(stream::QosOk()));
+// op(CommandHolder(stream::Consume()));
+// op(CommandHolder(stream::ConsumeOk()));
+// op(CommandHolder(stream::Cancel()));
+// op(CommandHolder(stream::Publish()));
+// op(CommandHolder(stream::Return()));
+// op(CommandHolder(stream::Deliver()));
+ return 0;
+}
+#endif /*!TESTS_ALLSEGMENTTYPES_H*/
diff --git a/RC9/qpid/cpp/src/tests/amqp_0_10/Map.cpp b/RC9/qpid/cpp/src/tests/amqp_0_10/Map.cpp
new file mode 100644
index 0000000000..efde967050
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/amqp_0_10/Map.cpp
@@ -0,0 +1,98 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "unit_test.h"
+#include "qpid/amqp_0_10/Map.h"
+#include "qpid/amqp_0_10/Array.h"
+#include "qpid/amqp_0_10/Struct32.h"
+#include "qpid/amqp_0_10/UnknownType.h"
+#include "qpid/amqp_0_10/Codec.h"
+#include <iostream>
+
+using namespace qpid::amqp_0_10;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(MapTestSuite)
+
+ QPID_AUTO_TEST_CASE(testGetSet) {
+ MapValue v;
+ v = Str8("foo");
+ BOOST_CHECK(v.get<Str8>());
+ BOOST_CHECK(!v.get<uint8_t>());
+ BOOST_CHECK_EQUAL(*v.get<Str8>(), "foo");
+
+ v = uint8_t(42);
+ BOOST_CHECK(!v.get<Str8>());
+ BOOST_CHECK(v.get<uint8_t>());
+ BOOST_CHECK_EQUAL(*v.get<uint8_t>(), 42);
+
+ v = uint16_t(12);
+ BOOST_CHECK(v.get<uint16_t>());
+ BOOST_CHECK_EQUAL(*v.get<uint16_t>(), 12);
+}
+
+template <class R> struct TestVisitor : public MapValue::Visitor<R> {
+ template <class T> R operator()(const T&) const { throw MapValue::BadTypeException(); }
+ R operator()(const R& r) const { return r; }
+};
+
+QPID_AUTO_TEST_CASE(testVisit) {
+ MapValue v;
+ v = Str8("foo");
+ BOOST_CHECK_EQUAL(v.apply_visitor(TestVisitor<Str8>()), "foo");
+ v = Uint16(42);
+ BOOST_CHECK_EQUAL(v.apply_visitor(TestVisitor<Uint16>()), 42);
+ try {
+ v.apply_visitor(TestVisitor<bool>());
+ BOOST_FAIL("Expecting exception");
+ }
+ catch(const MapValue::BadTypeException&) {}
+}
+
+
+QPID_AUTO_TEST_CASE(testEncodeMapValue) {
+ MapValue mv;
+ std::string data;
+ mv = Str8("hello");
+ Codec::encode(back_inserter(data))(mv);
+ BOOST_CHECK_EQUAL(data.size(), Codec::size(mv));
+ MapValue mv2;
+ Codec::decode(data.begin())(mv2);
+ BOOST_CHECK_EQUAL(mv2.getCode(), 0x85);
+ BOOST_REQUIRE(mv2.get<Str8>());
+ BOOST_CHECK_EQUAL(*mv2.get<Str8>(), "hello");
+}
+
+QPID_AUTO_TEST_CASE(testEncode) {
+ Map map;
+ std::string data;
+ map["A"] = true;
+ map["b"] = Str8("hello");
+ Codec::encode(back_inserter(data))(map);
+ BOOST_CHECK_EQUAL(Codec::size(map), data.size());
+ Map map2;
+ Codec::decode(data.begin())(map2);
+ BOOST_CHECK_EQUAL(map.size(), 2u);
+ BOOST_CHECK(map["A"].get<bool>());
+ BOOST_CHECK_EQUAL(*map["b"].get<Str8>(), "hello");
+}
+
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/amqp_0_10/ProxyTemplate.cpp b/RC9/qpid/cpp/src/tests/amqp_0_10/ProxyTemplate.cpp
new file mode 100644
index 0000000000..9d4fcb8935
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/amqp_0_10/ProxyTemplate.cpp
@@ -0,0 +1,49 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "unit_test.h"
+#include "qpid/amqp_0_10/ProxyTemplate.h"
+#include <boost/any.hpp>
+
+QPID_AUTO_TEST_SUITE(ProxyTemplateTestSuite)
+
+using namespace qpid::amqp_0_10;
+
+struct ToAny {
+ template <class T>
+ boost::any operator()(const T& t) { return boost::any(t); }
+};
+
+struct AnyProxy : public ProxyTemplate<ToAny, boost::any> {};
+
+QPID_AUTO_TEST_CASE(testAnyProxy) {
+ AnyProxy p;
+ boost::any a=p.connectionTune(1,2,3,4);
+ BOOST_CHECK_EQUAL(a.type().name(), typeid(connection::Tune).name());
+ connection::Tune* tune=boost::any_cast<connection::Tune>(&a);
+ BOOST_REQUIRE(tune);
+ BOOST_CHECK_EQUAL(tune->channelMax, 1u);
+ BOOST_CHECK_EQUAL(tune->maxFrameSize, 2u);
+ BOOST_CHECK_EQUAL(tune->heartbeatMin, 3u);
+ BOOST_CHECK_EQUAL(tune->heartbeatMax, 4u);
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/amqp_0_10/apply.cpp b/RC9/qpid/cpp/src/tests/amqp_0_10/apply.cpp
new file mode 100644
index 0000000000..5a67c28c79
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/amqp_0_10/apply.cpp
@@ -0,0 +1,99 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "unit_test.h"
+#include "qpid/amqp_0_10/specification.h"
+#include "qpid/amqp_0_10/ApplyControl.h"
+
+QPID_AUTO_TEST_SUITE(VisitorTestSuite)
+
+using namespace qpid::amqp_0_10;
+
+struct GetCode : public ApplyFunctor<uint8_t> {
+ template <class T> uint8_t operator()(const T&) const { return T::CODE; }
+};
+
+struct SetChannelMax : ApplyFunctor<void> {
+ template <class T> void operator()(T&) const { BOOST_FAIL(""); }
+ void operator()(connection::Tune& t) const { t.channelMax=42; }
+};
+
+struct TestFunctor {
+ typedef bool result_type;
+ bool operator()(const connection::Tune& tune) {
+ BOOST_CHECK_EQUAL(tune.channelMax, 1u);
+ BOOST_CHECK_EQUAL(tune.maxFrameSize, 2u);
+ BOOST_CHECK_EQUAL(tune.heartbeatMin, 3u);
+ BOOST_CHECK_EQUAL(tune.heartbeatMax, 4u);
+ return true;
+ }
+ template <class T>
+ bool operator()(const T&) { return false; }
+};
+
+QPID_AUTO_TEST_CASE(testApply) {
+ connection::Tune tune(1,2,3,4);
+ Control* p = &tune;
+
+ // boost oddity - without the cast we get undefined symbol errors.
+ BOOST_CHECK_EQUAL(apply(GetCode(), *p), (uint8_t)connection::Tune::CODE);
+
+ TestFunctor tf;
+ BOOST_CHECK(apply(tf, *p));
+
+ connection::Start start;
+ p = &start;
+ BOOST_CHECK(!apply(tf, *p));
+
+ apply(SetChannelMax(), tune);
+ BOOST_CHECK_EQUAL(tune.channelMax, 42);
+}
+
+struct VoidTestFunctor {
+ typedef void result_type;
+
+ int code;
+ VoidTestFunctor() : code() {}
+
+ void operator()(const connection::Tune& tune) {
+ BOOST_CHECK_EQUAL(tune.channelMax, 1u);
+ BOOST_CHECK_EQUAL(tune.maxFrameSize, 2u);
+ BOOST_CHECK_EQUAL(tune.heartbeatMin, 3u);
+ BOOST_CHECK_EQUAL(tune.heartbeatMax, 4u);
+ code=connection::Tune::CODE;
+ }
+ template <class T>
+ void operator()(const T&) { code=0xFF; }
+};
+
+QPID_AUTO_TEST_CASE(testApplyVoid) {
+ connection::Tune tune(1,2,3,4);
+ Control* p = &tune;
+ VoidTestFunctor tf;
+ apply(tf, *p);
+ BOOST_CHECK_EQUAL(uint8_t(connection::Tune::CODE), tf.code);
+
+ connection::Start start;
+ p = &start;
+ apply(tf, *p);
+ BOOST_CHECK_EQUAL(0xFF, tf.code);
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/amqp_0_10/handlers.cpp b/RC9/qpid/cpp/src/tests/amqp_0_10/handlers.cpp
new file mode 100644
index 0000000000..428643c802
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/amqp_0_10/handlers.cpp
@@ -0,0 +1,125 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "unit_test.h"
+#include "qpid/Exception.h"
+#include "qpid/amqp_0_10/Unit.h"
+#include "qpid/amqp_0_10/ControlHolder.h"
+#include "qpid/amqp_0_10/CommandHolder.h"
+#include "qpid/amqp_0_10/handlers.h"
+#include "qpid/amqp_0_10/specification.h"
+
+QPID_AUTO_TEST_SUITE(handler_tests)
+
+using namespace qpid::amqp_0_10;
+using namespace std;
+
+string called; // Set by called handler function
+
+// Note on handlers:
+//
+// Control and Command handlers are separate, both behave the same way,
+// so substitute "control or command" for command in the following.
+//
+// Command handlers derive from CommandHandler and implement functions
+// for all the commands they handle. Handling an unimplemented command
+// will raise NotImplementedException.
+//
+// Using virtual inheritance from CommandHandler allows multiple
+// handlers to be aggregated into one with multiple inheritance,
+// See test code for example.
+//
+// E.g. the existing broker model would have two control handlers:
+// - ConnectionHandler: ControlHandler for connection controls.
+// - SessionHandler: ControlHandler for session controls.
+// It would have class-command handlers for each AMQP class:
+// - QueueHandler, MessageHandler etc.. handle each class.
+// And an aggregate handler in place of BrokerAdapter
+// - BrokerCommandHandler: public QueueHandler, MessageHandler ...
+//
+// In other applications (e.g. cluster) any combination of commands
+// can be handled by a given handler. It _might_ simplify the code
+// to collaps ConnectionHandler and SessionHandler into a single
+// ControlHandler (or it might not.)
+
+struct TestExecutionHandler : public virtual CommandHandler {
+ void executionSync() { called = "executionSync"; }
+ // ... etc. for all execution commands
+};
+
+struct TestMessageHandler : public virtual CommandHandler {
+ void messageCancel(const Str8&) { called="messageCancel"; }
+ // ... etc.
+};
+
+// Aggregate handler for all recognised commands.
+struct TestCommandHandler :
+ public TestExecutionHandler,
+ public TestMessageHandler
+ // ... etc. handlers for all command classes.
+{}; // Nothing to do.
+
+
+// Sample unit handler, written as a static_visitor.
+// Note it could equally be written with if/else statements
+// in handle.
+//
+struct TestUnitHandler : public boost::static_visitor<void> {
+ TestCommandHandler handler;
+ void handle(const Unit& u) { u.applyVisitor(*this); }
+
+ void operator()(const Body&) { called="Body"; }
+ void operator()(const Header&) { called="Header"; }
+ void operator()(const ControlHolder&) { throw qpid::Exception("I don't do controls."); }
+ void operator()(const CommandHolder& c) { c.invoke(handler); }
+};
+
+QPID_AUTO_TEST_CASE(testHandlers) {
+ TestUnitHandler handler;
+ Unit u;
+
+ u = Body();
+ handler.handle(u);
+ BOOST_CHECK_EQUAL("Body", called);
+
+ u = Header();
+ handler.handle(u);
+ BOOST_CHECK_EQUAL("Header", called);
+
+ // in_place<Foo>(...) is equivalent to Foo(...) but
+ // constructs Foo directly in the holder, avoiding
+ // a copy.
+
+ u = CommandHolder(in_place<execution::Sync>());
+ handler.handle(u);
+ BOOST_CHECK_EQUAL("executionSync", called);
+
+ u = ControlHolder(in_place<connection::Start>(Map(), Str16Array(), Str16Array()));
+ try {
+ handler.handle(u);
+ } catch (const qpid::Exception&) {}
+
+ u = CommandHolder(in_place<message::Cancel>(Str8()));
+ handler.handle(u);
+ BOOST_CHECK_EQUAL("messageCancel", called);
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/amqp_0_10/serialize.cpp b/RC9/qpid/cpp/src/tests/amqp_0_10/serialize.cpp
new file mode 100644
index 0000000000..0cfeb8d28d
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/amqp_0_10/serialize.cpp
@@ -0,0 +1,429 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "unit_test.h"
+#include "allSegmentTypes.h"
+
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/Buffer.h"
+
+#include "qpid/amqp_0_10/Packer.h"
+#include "qpid/amqp_0_10/built_in_types.h"
+#include "qpid/amqp_0_10/Codec.h"
+#include "qpid/amqp_0_10/specification.h"
+#include "qpid/amqp_0_10/ControlHolder.h"
+#include "qpid/amqp_0_10/Struct32.h"
+#include "qpid/amqp_0_10/FrameHeader.h"
+#include "qpid/amqp_0_10/Map.h"
+#include "qpid/amqp_0_10/Unit.h"
+#include "tests/allSegmentTypes.h"
+
+#include <boost/test/test_case_template.hpp>
+#include <boost/type_traits/is_arithmetic.hpp>
+#include <boost/utility/enable_if.hpp>
+#include <boost/optional.hpp>
+#include <boost/mpl/vector.hpp>
+#include <boost/mpl/back_inserter.hpp>
+#include <boost/mpl/copy.hpp>
+#include <boost/mpl/empty_sequence.hpp>
+#include <boost/current_function.hpp>
+#include <iterator>
+#include <string>
+#include <sstream>
+#include <iostream>
+#include <netinet/in.h>
+
+// Missing operators needed for tests.
+namespace boost {
+template <class T, size_t N>
+std::ostream& operator<<(std::ostream& out, const array<T,N>& a) {
+ std::ostream_iterator<T> o(out, " ");
+ std::copy(a.begin(), a.end(), o);
+ return out;
+}
+} // boost
+
+QPID_AUTO_TEST_SUITE(SerializeTestSuite)
+
+using namespace std;
+namespace mpl=boost::mpl;
+using namespace qpid::amqp_0_10;
+using qpid::framing::in_place;
+
+template <class A, class B> struct concat2 { typedef typename mpl::copy<B, typename mpl::back_inserter<A> >::type type; };
+template <class A, class B, class C> struct concat3 { typedef typename concat2<A, typename concat2<B, C>::type>::type type; };
+template <class A, class B, class C, class D> struct concat4 { typedef typename concat2<A, typename concat3<B, C, D>::type>::type type; };
+
+typedef mpl::vector<Boolean, Char, Int32, Int64, Int8, Uint16, CharUtf32, Uint32, Uint64, Bin8, Uint8>::type IntegralTypes;
+typedef mpl::vector<Bin1024, Bin128, Bin16, Bin256, Bin32, Bin40, Bin512, Bin64, Bin72>::type BinTypes;
+typedef mpl::vector<Double, Float>::type FloatTypes;
+typedef mpl::vector<SequenceNo, Uuid, Datetime, Dec32, Dec64> FixedSizeClassTypes;
+typedef mpl::vector<Map, Vbin8, Str8Latin, Str8, Str8Utf16, Vbin16, Str16Latin, Str16, Str16Utf16, Vbin32> VariableSizeTypes;
+
+typedef concat4<IntegralTypes, BinTypes, FloatTypes, FixedSizeClassTypes>::type FixedSizeTypes;
+typedef concat2<FixedSizeTypes, VariableSizeTypes>::type AllTypes;
+
+// TODO aconway 2008-02-20: should test 64 bit integrals for order also.
+QPID_AUTO_TEST_CASE(testNetworkByteOrder) {
+ string data;
+
+ uint32_t l = 0x11223344;
+ Codec::encode(std::back_inserter(data))(l);
+ uint32_t enc=reinterpret_cast<const uint32_t&>(*data.data());
+ uint32_t l2 = ntohl(enc);
+ BOOST_CHECK_EQUAL(l, l2);
+
+ data.clear();
+ uint16_t s = 0x1122;
+ Codec::encode(std::back_inserter(data))(s);
+ uint32_t s2 = ntohs(*reinterpret_cast<const uint32_t*>(data.data()));
+ BOOST_CHECK_EQUAL(s, s2);
+}
+
+QPID_AUTO_TEST_CASE(testSetLimit) {
+ typedef Codec::Encoder<back_insert_iterator<string> > Encoder;
+ string data;
+ Encoder encode(back_inserter(data), 3);
+ encode('1')('2')('3');
+ try {
+ encode('4');
+ BOOST_FAIL("Expected exception");
+ } catch (...) {} // FIXME aconway 2008-04-03: catch proper exception
+ BOOST_CHECK_EQUAL(data, "123");
+}
+
+QPID_AUTO_TEST_CASE(testScopedLimit) {
+ typedef Codec::Encoder<back_insert_iterator<string> > Encoder;
+ string data;
+ Encoder encode(back_inserter(data), 10);
+ encode(Str8("123")); // 4 bytes
+ {
+ Encoder::ScopedLimit l(encode, 3);
+ encode('a')('b')('c');
+ try {
+ encode('d');
+ BOOST_FAIL("Expected exception");
+ } catch(...) {} // FIXME aconway 2008-04-03: catch proper exception
+ }
+ BOOST_CHECK_EQUAL(data, "\003123abc");
+ encode('x')('y')('z');
+ try {
+ encode('!');
+ BOOST_FAIL("Expected exception");
+ } catch(...) {} // FIXME aconway 2008-04-03: catch proper exception
+ BOOST_CHECK_EQUAL(data.size(), 10u);
+}
+
+// Assign test values to the various types.
+void testValue(bool& b) { b = true; }
+void testValue(Bit&) { }
+template <class T> typename boost::enable_if<boost::is_arithmetic<T> >::type testValue(T& n) { n=42; }
+void testValue(CharUtf32& c) { c = 43; }
+void testValue(long long& l) { l = 0x012345; }
+void testValue(Datetime& dt) { dt = qpid::sys::now(); }
+void testValue(Uuid& uuid) { uuid=Uuid(true); }
+template <class E, class M> void testValue(Decimal<E,M>& d) { d.exponent=2; d.mantissa=0x1122; }
+void testValue(SequenceNo& s) { s = 42; }
+template <size_t N> void testValue(Bin<N>& a) { a.assign(42); }
+template <class T, class S, int Unique> void testValue(SerializableString<T, S, Unique>& s) {
+ char msg[]="foobar";
+ s.assign(msg, msg+sizeof(msg));
+}
+void testValue(Str16& s) { s = "the quick brown fox jumped over the lazy dog"; }
+void testValue(Str8& s) { s = "foobar"; }
+void testValue(Map& m) { m["s"] = Str8("foobar"); m["b"] = true; m["c"] = uint16_t(42); }
+
+//typedef mpl::vector<Str8, Str16>::type TestTypes;
+/*BOOST_AUTO_TEST_CASE_TEMPLATE(testEncodeDecode, T, AllTypes)
+{
+ string data;
+ T t;
+ testValue(t);
+ Codec::encode(std::back_inserter(data))(t);
+
+ BOOST_CHECK_EQUAL(Codec::size(t), data.size());
+
+ T t2;
+ Codec::decode(data.begin())(t2);
+ BOOST_CHECK_EQUAL(t,t2);
+}
+*/
+
+struct TestMe {
+ bool encoded, decoded;
+ char value;
+ TestMe(char v) : encoded(), decoded(), value(v) {}
+ template <class S> void encode(S& s) const {
+ const_cast<TestMe*>(this)->encoded=true; s(value);
+ }
+ template <class S> void decode(S& s) { decoded=true; s(value); }
+ template <class S> void serialize(S& s) { s.split(*this); }
+};
+
+QPID_AUTO_TEST_CASE(testSplit) {
+ string data;
+ TestMe t1('x');
+ Codec::encode(std::back_inserter(data))(t1);
+ BOOST_CHECK(t1.encoded);
+ BOOST_CHECK(!t1.decoded);
+ BOOST_CHECK_EQUAL(data, "x");
+
+ TestMe t2('y');
+ Codec::decode(data.begin())(t2);
+ BOOST_CHECK(!t2.encoded);
+ BOOST_CHECK(t2.decoded);
+ BOOST_CHECK_EQUAL(t2.value, 'x');
+}
+
+QPID_AUTO_TEST_CASE(testControlEncodeDecode) {
+ string data;
+ Control::Holder h(in_place<connection::Tune>(1,2,3,4));
+ Codec::encode(std::back_inserter(data))(h);
+
+ BOOST_CHECK_EQUAL(data.size(), Codec::size(h));
+
+ Codec::Decoder<string::iterator> decode(data.begin());
+ Control::Holder h2;
+ decode(h2);
+
+ BOOST_REQUIRE(h2.get());
+ BOOST_CHECK_EQUAL(h2.get()->getClassCode(), connection::CODE);
+ BOOST_CHECK_EQUAL(h2.get()->getCode(), uint8_t(connection::Tune::CODE));
+ connection::Tune& tune=static_cast<connection::Tune&>(*h2.get());
+ BOOST_CHECK_EQUAL(tune.channelMax, 1u);
+ BOOST_CHECK_EQUAL(tune.maxFrameSize, 2u);
+ BOOST_CHECK_EQUAL(tune.heartbeatMin, 3u);
+ BOOST_CHECK_EQUAL(tune.heartbeatMax, 4u);
+}
+
+QPID_AUTO_TEST_CASE(testStruct32) {
+ message::DeliveryProperties dp;
+ dp.priority=message::MEDIUM;
+ dp.routingKey="foo";
+ Struct32 s(dp);
+ string data;
+ Codec::encode(back_inserter(data))(s);
+
+ uint32_t structSize; // Starts with size
+ Codec::decode(data.begin())(structSize);
+ BOOST_CHECK_EQUAL(structSize, Codec::size(dp) + 2); // +2 for code
+ BOOST_CHECK_EQUAL(structSize, data.size()-4); // encoded body
+
+ BOOST_CHECK_EQUAL(data.size(), Codec::size(s));
+ Struct32 s2;
+ Codec::decode(data.begin())(s2);
+ message::DeliveryProperties* dp2 = s2.getIf<message::DeliveryProperties>();
+ BOOST_REQUIRE(dp2);
+ BOOST_CHECK_EQUAL(dp2->priority, message::MEDIUM);
+ BOOST_CHECK_EQUAL(dp2->routingKey, "foo");
+}
+
+QPID_AUTO_TEST_CASE(testStruct32Unknown) {
+ // Verify we can recode an unknown struct unchanged.
+ Struct32 s;
+ string data;
+ Codec::encode(back_inserter(data))(uint32_t(10));
+ data.append(10, 'X');
+ Codec::decode(data.begin())(s);
+ string data2;
+ Codec::encode(back_inserter(data2))(s);
+ BOOST_CHECK_EQUAL(data.size(), data2.size());
+ BOOST_CHECK_EQUAL(data, data2);
+}
+
+struct DummyPacked {
+ static const uint8_t PACK=1;
+ boost::optional<char> i, j;
+ char k;
+ Bit l,m;
+ DummyPacked(char a=0, char b=0, char c=0) : i(a), j(b), k(c), l(), m() {}
+ template <class S> void serialize(S& s) { s(i)(j)(k)(l)(m); }
+};
+
+Packer<DummyPacked> serializable(DummyPacked& d) { return Packer<DummyPacked>(d); }
+
+QPID_AUTO_TEST_CASE(testPackBits) {
+ DummyPacked d('a','b','c');
+ BOOST_CHECK_EQUAL(packBits(d), 7u);
+ d.j = boost::none;
+ BOOST_CHECK_EQUAL(packBits(d), 5u);
+ d.m = true;
+ BOOST_CHECK_EQUAL(packBits(d), 0x15u);
+}
+
+
+QPID_AUTO_TEST_CASE(testPacked) {
+ string data;
+
+ Codec::encode(back_inserter(data))('a')(boost::optional<char>('b'))(boost::optional<char>())('c');
+ BOOST_CHECK_EQUAL(data, "abc");
+ data.clear();
+
+ DummyPacked dummy('a','b','c');
+
+ Codec::encode(back_inserter(data))(dummy);
+ BOOST_CHECK_EQUAL(data.size(), 4u);
+ BOOST_CHECK_EQUAL(data, string("\007abc"));
+ data.clear();
+
+ dummy.i = boost::none;
+ Codec::encode(back_inserter(data))(dummy);
+ BOOST_CHECK_EQUAL(data, string("\6bc"));
+ data.clear();
+
+ const char* missing = "\5xy";
+ Codec::decode(missing)(dummy);
+ BOOST_CHECK(dummy.i);
+ BOOST_CHECK_EQUAL(*dummy.i, 'x');
+ BOOST_CHECK(!dummy.j);
+ BOOST_CHECK_EQUAL(dummy.k, 'y');
+}
+
+QPID_AUTO_TEST_CASE(testUnitControl) {
+ string data;
+ Control::Holder h(in_place<connection::Tune>(1,2,3,4));
+ Codec::encode(std::back_inserter(data))(h);
+
+ Unit unit(FrameHeader(FIRST_FRAME|LAST_FRAME, CONTROL));
+ Codec::decode(data.begin())(unit);
+
+ BOOST_REQUIRE(unit.get<ControlHolder>());
+
+ string data2;
+ Codec::encode(back_inserter(data2))(unit);
+
+ BOOST_CHECK_EQUAL(data, data2);
+}
+
+QPID_AUTO_TEST_CASE(testArray) {
+ ArrayDomain<char> a;
+ a.resize(3, 'x');
+ string data;
+ Codec::encode(back_inserter(data))(a);
+
+ ArrayDomain<char> b;
+ Codec::decode(data.begin())(b);
+ BOOST_CHECK_EQUAL(b.size(), 3u);
+ string data3;
+ Codec::encode(back_inserter(data3))(a);
+ BOOST_CHECK_EQUAL(data, data3);
+
+ Array x;
+ Codec::decode(data.begin())(x);
+ BOOST_CHECK_EQUAL(x.size(), 3u);
+ BOOST_CHECK_EQUAL(x[0].size(), 1u);
+ BOOST_CHECK_EQUAL(*x[0].begin(), 'x');
+ BOOST_CHECK_EQUAL(*x[2].begin(), 'x');
+
+ string data2;
+ Codec::encode(back_inserter(data2))(x);
+ BOOST_CHECK_EQUAL(data,data2);
+}
+
+QPID_AUTO_TEST_CASE(testStruct) {
+ string data;
+
+ message::DeliveryProperties dp;
+ BOOST_CHECK(!dp.discardUnroutable);
+ dp.immediate = true;
+ dp.redelivered = false;
+ dp.priority = message::MEDIUM;
+ dp.exchange = "foo";
+
+ Codec::encode(back_inserter(data))(dp);
+ // Skip 4 bytes size, little-endian decode for pack bits.
+ uint16_t encodedBits=uint8_t(data[5]);
+ encodedBits <<= 8;
+ encodedBits += uint8_t(data[4]);
+ BOOST_CHECK_EQUAL(encodedBits, packBits(dp));
+
+ data.clear();
+ Struct32 h(dp);
+ Codec::encode(back_inserter(data))(h);
+
+ Struct32 h2;
+ Codec::decode(data.begin())(h2);
+ BOOST_CHECK_EQUAL(h2.getClassCode(), Uint8(message::DeliveryProperties::CLASS_CODE));
+ BOOST_CHECK_EQUAL(h2.getCode(), Uint8(message::DeliveryProperties::CODE));
+ message::DeliveryProperties* dp2 =
+ dynamic_cast<message::DeliveryProperties*>(h2.get());
+ BOOST_CHECK(dp2);
+ BOOST_CHECK(!dp2->discardUnroutable);
+ BOOST_CHECK(dp2->immediate);
+ BOOST_CHECK(!dp2->redelivered);
+ BOOST_CHECK_EQUAL(dp2->priority, message::MEDIUM);
+ BOOST_CHECK_EQUAL(dp2->exchange, "foo");
+}
+
+struct RecodeUnit {
+ template <class T>
+ void operator() (const T& t) {
+ BOOST_MESSAGE(BOOST_CURRENT_FUNCTION << " called with: " << t);
+ using qpid::framing::Buffer;
+ using qpid::framing::AMQFrame;
+
+ session::Header sh;
+ BOOST_CHECK_EQUAL(Codec::size(sh), 2u);
+
+ // Encode unit.
+ Unit u(t);
+ string data;
+ Codec::encode(back_inserter(data))(u.getHeader())(u);
+ data.push_back(char(0xCE)); // Preview end-of-frame
+
+ // Decode AMQFrame
+ Buffer buf(&data[0], data.size());
+ AMQFrame f;
+ f.decode(buf);
+ BOOST_MESSAGE("AMQFrame decoded: " << f);
+ // Encode AMQFrame
+ string data2(f.size(), ' ');
+ Buffer buf2(&data2[0], data.size());
+ f.encode(buf2);
+
+ // Verify encoded by unit == encoded by AMQFrame
+ BOOST_CHECK_MESSAGE(data == data2, BOOST_CURRENT_FUNCTION);
+
+ // Decode unit
+ // FIXME aconway 2008-04-15: must set limit to decode a header.
+ Codec::Decoder<string::iterator> decode(data2.begin(), data2.size()-1);
+
+ FrameHeader h;
+ decode(h);
+ BOOST_CHECK_EQUAL(u.getHeader(), h);
+ Unit u2(h);
+ decode(u2);
+
+ // Re-encode unit
+ string data3;
+ Codec::encode(back_inserter(data3))(u2.getHeader())(u2);
+ data3.push_back(char(0xCE)); // Preview end-of-frame
+
+ BOOST_CHECK_MESSAGE(data3 == data2, BOOST_CURRENT_FUNCTION);
+ }
+};
+
+QPID_AUTO_TEST_CASE(testSerializeAllSegmentTypes) {
+ RecodeUnit recode;
+ allSegmentTypes(recode);
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/benchmark b/RC9/qpid/cpp/src/tests/benchmark
new file mode 100755
index 0000000000..c075837847
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/benchmark
@@ -0,0 +1,95 @@
+#!/bin/sh
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# A basic "benchmark" to generate performacne samples of throughput
+# and latency against a single cluster member while they are replicating.
+#
+# Must be run in the qpid src/tests build directory.
+#
+
+usage() {
+cat <<EOF
+Usage: $0 [options] -- client hosts --- broker hosts
+Read the script for options.
+EOF
+}
+# Defaults
+TESTDIR=${TESTDIR:-$PWD} # Absolute path to test exes on all hosts.
+SCRIPTDIR=${SCRIPTDIR:-`dirname $0`} # Path to local test scripts directory.
+SAMPLES=10 # Runs of each test.
+COUNT=${COUNT:-10000} # Count for pub/sub tests.
+SIZE=${SIZE:-600} # Size of messages
+ECHO=${ECHO:-1000} # Count for echo test.
+NSUBS=${NSUBS:-4}
+NPUBS=${NPUBS:-4}
+
+collect() { eval $COLLECT=\""\$$COLLECT $*"\"; }
+COLLECT=ARGS
+while test $# -gt 0; do
+ case $1 in
+ --testdir) TESTDIR=$2 ; shift 2 ;;
+ --samples) SAMPLES=$2 ; shift 2 ;;
+ --count) COUNT=$2 ; shift 2 ;;
+ --echos) ECHO=$2 ; shift 2 ;;
+ --size) SIZE=$2 ; shift 2 ;;
+ --nsubs) NSUBS=$2 ; shift 2 ;;
+ --npubs) NPUBS=$2 ; shift 2 ;;
+ --) COLLECT=CLIENTARG; shift ;;
+ ---) COLLECT=BROKERARG; shift;;
+ *) collect $1; shift ;;
+ esac
+done
+
+CLIENTS=${CLIENTARG:-$CLIENTS}
+BROKERS=${BROKERARG:-$BROKERS}
+test -z "$CLIENTS" && { echo "Must specify at least one client host."; exit 1; }
+test -z "$BROKERS" && { echo "Must specify at least one broker host."; exit 1; }
+
+export TESTDIR # For perfdist
+CLIENTS=($CLIENTS) # Convert to array
+BROKERS=($BROKERS)
+trap "rm -f $FILES" EXIT
+
+dosamples() {
+ FILE=`mktemp`
+ FILES="$FILES $FILE"
+ TABS=`echo "$HEADING" | sed s'/[^ ]//g'`
+ {
+ echo "\"$*\"$TABS"
+ echo "$HEADING"
+ for (( i=0; i<$SAMPLES; ++i)) ; do echo "`$*`" ; done
+ echo
+ } | tee $FILE
+}
+
+HEADING="pub sub total Mb"
+dosamples $SCRIPTDIR/perfdist --size $SIZE --count $COUNT --nsubs $NSUBS --npubs $NPUBS -s -- ${CLIENTS[*]} --- ${BROKERS[*]}
+HEADING="pub"
+dosamples ssh -A ${CLIENTS[0]} $TESTDIR/publish --routing-key perftest0 --size $SIZE --count $COUNT -s -b ${BROKERS[0]}
+HEADING="sub"
+dosamples ssh -A ${CLIENTS[0]} $TESTDIR/consume --queue perftest0 -s --count $COUNT -b ${BROKERS[0]}
+HEADING="min max avg"
+dosamples ssh -A ${CLIENTS[0]} $TESTDIR/echotest --count $ECHO -s -b ${BROKERS[0]}
+
+echo
+echo "Tab separated spreadsheet (also saved as benchmark.tab):"
+echo
+
+echo "benchmark -- ${CLIENTS[*]} --- ${BROKERS[*]} " | tee benchmark.tab
+paste $FILES | tee -a benchmark.tab
diff --git a/RC9/qpid/cpp/src/tests/client_test.cpp b/RC9/qpid/cpp/src/tests/client_test.cpp
new file mode 100644
index 0000000000..204c2c4b71
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/client_test.cpp
@@ -0,0 +1,149 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/**
+ * This file provides a simple test (and example) of basic
+ * functionality including declaring an exchange and a queue, binding
+ * these together, publishing a message and receiving that message
+ * asynchronously.
+ */
+
+#include <iostream>
+
+#include "TestOptions.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/Session.h"
+#include "qpid/framing/FrameSet.h"
+#include "qpid/framing/all_method_bodies.h"
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace qpid::framing;
+using std::string;
+
+struct Args : public TestOptions {
+ uint msgSize;
+ bool verbose;
+
+ Args() : TestOptions("Simple test of Qpid c++ client; sends and receives a single message."), msgSize(26)
+ {
+ addOptions()
+ ("size", optValue(msgSize, "N"), "message size")
+ ("verbose", optValue(verbose), "print out some status messages");
+ }
+};
+
+const std::string chars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
+
+std::string generateData(uint size)
+{
+ if (size < chars.length()) {
+ return chars.substr(0, size);
+ }
+ std::string data;
+ for (uint i = 0; i < (size / chars.length()); i++) {
+ data += chars;
+ }
+ data += chars.substr(0, size % chars.length());
+ return data;
+}
+
+void print(const std::string& text, const Message& msg)
+{
+ std::cout << text;
+ if (msg.getData().size() > 16) {
+ std::cout << msg.getData().substr(0, 16) << "...";
+ } else {
+ std::cout << msg.getData();
+ }
+ std::cout << std::endl;
+}
+
+int main(int argc, char** argv)
+{
+ try {
+ Args opts;
+ opts.parse(argc, argv);
+
+ //Connect to the broker:
+ Connection connection;
+ opts.open(connection);
+ if (opts.verbose) std::cout << "Opened connection." << std::endl;
+
+ //Create and open a session on the connection through which
+ //most functionality is exposed:
+ Session session = connection.newSession();
+ if (opts.verbose) std::cout << "Opened session." << std::endl;
+
+
+ //'declare' the exchange and the queue, which will create them
+ //as they don't exist
+ session.exchangeDeclare(arg::exchange="MyExchange", arg::type="direct");
+ if (opts.verbose) std::cout << "Declared exchange." << std::endl;
+ session.queueDeclare(arg::queue="MyQueue", arg::autoDelete=true, arg::exclusive=true);
+ if (opts.verbose) std::cout << "Declared queue." << std::endl;
+
+ //now bind the queue to the exchange
+ session.exchangeBind(arg::exchange="MyExchange", arg::queue="MyQueue", arg::bindingKey="MyKey");
+ if (opts.verbose) std::cout << "Bound queue to exchange." << std::endl;
+
+ //create and send a message to the exchange using the routing
+ //key we bound our queue with:
+ Message msgOut(generateData(opts.msgSize));
+ msgOut.getDeliveryProperties().setRoutingKey("MyKey");
+ session.messageTransfer(arg::destination="MyExchange", arg::content=msgOut, arg::acceptMode=1);
+ if (opts.verbose) print("Published message: ", msgOut);
+
+ //subscribe to the queue, add sufficient credit and then get
+ //incoming 'frameset', check that its a message transfer and
+ //then convert it to a message (see Dispatcher and
+ //SubscriptionManager utilties for common reusable patterns at
+ //a higher level)
+ session.messageSubscribe(arg::queue="MyQueue", arg::destination="MyId");
+ session.messageFlow(arg::destination="MyId", arg::unit=0, arg::value=1); //credit for one message
+ session.messageFlow(arg::destination="MyId", arg::unit=1, arg::value=0xFFFFFFFF); //credit for infinite bytes
+ if (opts.verbose) std::cout << "Subscribed to queue." << std::endl;
+ FrameSet::shared_ptr incoming = session.get();
+ if (incoming->isA<MessageTransferBody>()) {
+ Message msgIn(*incoming);
+ if (msgIn.getData() == msgOut.getData()) {
+ if (opts.verbose) std::cout << "Received the exepected message." << std::endl;
+ session.messageAccept(SequenceSet(msgIn.getId()));
+ session.markCompleted(msgIn.getId(), true, true);
+ } else {
+ print("Received an unexepected message: ", msgIn);
+ }
+ } else {
+ throw Exception("Unexpected command received");
+ }
+
+ //close the session & connection
+ session.close();
+ if (opts.verbose) std::cout << "Closed session." << std::endl;
+ connection.close();
+ if (opts.verbose) std::cout << "Closed connection." << std::endl;
+ return 0;
+ } catch(const std::exception& e) {
+ std::cout << e.what() << std::endl;
+ }
+ return 1;
+}
diff --git a/RC9/qpid/cpp/src/tests/cluster.mk b/RC9/qpid/cpp/src/tests/cluster.mk
new file mode 100644
index 0000000000..1f027ccb4c
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/cluster.mk
@@ -0,0 +1,41 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+if HAVE_LIBCPG
+
+#
+# Cluster tests makefile fragment, to be included in Makefile.am
+#
+
+# NOTE: Programs using the openais library must be run with gid=ais
+# You should do "newgrp ais" before running the tests to run these.
+#
+
+
+# ais_check checks pre-requisites for cluster tests and runs them if ok.
+TESTS+=ais_check
+EXTRA_DIST+=ais_check start_cluster stop_cluster
+
+check_PROGRAMS+=cluster_test
+cluster_test_SOURCES=unit_test.cpp cluster_test.cpp
+cluster_test_LDADD=$(lib_client) ../cluster.la -lboost_unit_test_framework
+
+unit_test_LDADD+=../cluster.la
+
+endif
diff --git a/RC9/qpid/cpp/src/tests/cluster_test.cpp b/RC9/qpid/cpp/src/tests/cluster_test.cpp
new file mode 100644
index 0000000000..f4a38ae861
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/cluster_test.cpp
@@ -0,0 +1,648 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test_tools.h"
+#include "unit_test.h"
+#include "ForkedBroker.h"
+#include "BrokerFixture.h"
+
+#include "qpid/client/Connection.h"
+#include "qpid/client/ConnectionAccess.h"
+#include "qpid/client/Session.h"
+#include "qpid/client/FailoverListener.h"
+#include "qpid/cluster/Cluster.h"
+#include "qpid/cluster/Cpg.h"
+#include "qpid/cluster/DumpClient.h"
+#include "qpid/framing/AMQBody.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/framing/enum.h"
+#include "qpid/log/Logger.h"
+
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <string>
+#include <iostream>
+#include <iterator>
+#include <vector>
+#include <set>
+#include <algorithm>
+#include <iterator>
+
+namespace std { // ostream operators in std:: namespace
+template <class T>
+ostream& operator<<(ostream& o, const std::set<T>& s) { return seqPrint(o, s); }
+}
+
+
+QPID_AUTO_TEST_SUITE(cluster)
+
+using namespace std;
+using namespace qpid;
+using namespace qpid::cluster;
+using namespace qpid::framing;
+using namespace qpid::client;
+using qpid::sys::TIME_SEC;
+using qpid::broker::Broker;
+using boost::shared_ptr;
+using qpid::cluster::Cluster;
+
+/** Parse broker & cluster options */
+Broker::Options parseOpts(size_t argc, const char* argv[]) {
+ Broker::Options opts;
+ Plugin::addOptions(opts); // Pick up cluster options.
+ opts.parse(argc, argv, "", true); // Allow-unknown for --load-module
+ return opts;
+}
+
+/** Cluster fixture is a vector of ports for the replicas.
+ *
+ * At most one replica (by default replica 0) is in the current
+ * process, all others are forked as children.
+ */
+class ClusterFixture : public vector<uint16_t> {
+ string name;
+ std::auto_ptr<BrokerFixture> localBroker;
+ int localIndex;
+ std::vector<shared_ptr<ForkedBroker> > forkedBrokers;
+
+ public:
+ /** @param localIndex can be -1 meaning don't automatically start a local broker.
+ * A local broker can be started with addLocal().
+ */
+ ClusterFixture(size_t n, int localIndex=0);
+ void add(size_t n) { for (size_t i=0; i < n; ++i) add(); }
+ void add(); // Add a broker.
+ void addLocal(); // Add a local broker.
+ void setup();
+
+ bool hasLocal() const { return localIndex >= 0 && size_t(localIndex) < size(); }
+
+ /** Kill a forked broker with sig, or shutdown localBroker if n==0. */
+ void kill(size_t n, int sig=SIGINT) {
+ if (n == size_t(localIndex))
+ localBroker->broker->shutdown();
+ else
+ forkedBrokers[n]->kill(sig);
+ }
+
+ /** Kill a broker and suppress errors from connection. */
+ void killWithSilencer(size_t n, client::Connection& c, int sig=SIGINT) {
+ ScopedSuppressLogging sl;
+ kill(n,sig);
+ try { c.close(); } catch(...) {}
+ }
+};
+
+ClusterFixture::ClusterFixture(size_t n, int localIndex_) : name(Uuid(true).str()), localIndex(localIndex_) {
+ add(n);
+}
+
+void ClusterFixture::add() {
+ if (size() != size_t(localIndex)) { // fork a broker process.
+ std::ostringstream os; os << "fork" << size();
+ std::string prefix = os.str();
+ const char* argv[] = {
+ "qpidd " __FILE__ ,
+ "--no-module-dir",
+ "--load-module=../.libs/cluster.so",
+ "--cluster-name", name.c_str(),
+ "--auth=no", "--no-data-dir",
+ "--log-prefix", prefix.c_str(),
+ };
+ size_t argc = sizeof(argv)/sizeof(argv[0]);
+ forkedBrokers.push_back(shared_ptr<ForkedBroker>(new ForkedBroker(argc, argv)));
+ push_back(forkedBrokers.back()->getPort());
+ }
+ else { // Run in this process
+ addLocal();
+ }
+}
+
+void ClusterFixture::addLocal() {
+ assert(int(size()) == localIndex || localIndex == -1);
+ localIndex = size();
+ const char* argv[] = {
+ "qpidd " __FILE__ ,
+ "--load-module=../.libs/cluster.so",
+ "--cluster-name", name.c_str(),
+ "--auth=no", "--no-data-dir"
+ };
+ size_t argc = sizeof(argv)/sizeof(argv[0]);
+ ostringstream os; os << "local" << localIndex;
+ qpid::log::Logger::instance().setPrefix(os.str());
+ localBroker.reset(new BrokerFixture(parseOpts(argc, argv)));
+ push_back(localBroker->getPort());
+ forkedBrokers.push_back(shared_ptr<ForkedBroker>());
+}
+
+ostream& operator<<(ostream& o, const cpg_name* n) {
+ return o << qpid::cluster::Cpg::str(*n);
+}
+
+ostream& operator<<(ostream& o, const cpg_address& a) {
+ return o << "(" << a.nodeid <<","<<a.pid<<","<<a.reason<<")";
+}
+
+template <class T>
+ostream& operator<<(ostream& o, const pair<T*, int>& array) {
+ o << "{ ";
+ ostream_iterator<cpg_address> i(o, " ");
+ copy(array.first, array.first+array.second, i);
+ o << "}";
+ return o;
+}
+
+template <class C> set<uint16_t> makeSet(const C& c) {
+ set<uint16_t> s;
+ std::copy(c.begin(), c.end(), std::inserter(s, s.begin()));
+ return s;
+}
+
+template <class T> std::set<uint16_t> knownBrokerPorts(T& source, int n=-1) {
+ vector<Url> urls = source.getKnownBrokers();
+ if (n >= 0 && unsigned(n) != urls.size()) {
+ BOOST_MESSAGE("knownBrokerPorts waiting for " << n << ": " << urls);
+ // Retry up to 10 secs in .1 second intervals.
+ for (size_t retry=100; urls.size() != unsigned(n) && retry != 0; --retry) {
+ ::usleep(1000*100); // 0.1 secs
+ urls = source.getKnownBrokers();
+ }
+ }
+ BOOST_MESSAGE("knownBrokerPorts expecting " << n << ": " << urls);
+ set<uint16_t> s;
+ for (vector<Url>::const_iterator i = urls.begin(); i != urls.end(); ++i)
+ s.insert((*i)[0].get<TcpAddress>()->port);
+ return s;
+}
+
+class Sender {
+ public:
+ Sender(boost::shared_ptr<ConnectionImpl> ci, uint16_t ch) : connection(ci), channel(ch) {}
+ void send(const AMQBody& body, bool firstSeg, bool lastSeg, bool firstFrame, bool lastFrame) {
+ AMQFrame f(body);
+ f.setChannel(channel);
+ f.setFirstSegment(firstSeg);
+ f.setLastSegment(lastSeg);
+ f.setFirstFrame(firstFrame);
+ f.setLastFrame(lastFrame);
+ connection->handle(f);
+ }
+
+ private:
+ boost::shared_ptr<ConnectionImpl> connection;
+ uint16_t channel;
+};
+
+int64_t getMsgSequence(const Message& m) {
+ return m.getMessageProperties().getApplicationHeaders().getAsInt64("qpid.msg_sequence");
+}
+
+QPID_AUTO_TEST_CASE(testSequenceOptions) {
+ // Make sure the exchange qpid.msg_sequence property is properly replicated.
+ ClusterFixture cluster(1);
+ Client c0(cluster[0], "c0");
+ FieldTable args;
+ args.setInt("qpid.msg_sequence", 1); // FIXME aconway 2008-11-11: works with "qpid.sequence_counter"??
+ c0.session.queueDeclare(arg::queue="q");
+ c0.session.exchangeDeclare(arg::exchange="ex", arg::type="direct", arg::arguments=args);
+ c0.session.exchangeBind(arg::exchange="ex", arg::queue="q", arg::bindingKey="k");
+ c0.session.messageTransfer(arg::content=Message("1", "k"), arg::destination="ex");
+ c0.session.messageTransfer(arg::content=Message("2", "k"), arg::destination="ex");
+ BOOST_CHECK_EQUAL(1, getMsgSequence(c0.subs.get("q", TIME_SEC)));
+ BOOST_CHECK_EQUAL(2, getMsgSequence(c0.subs.get("q", TIME_SEC)));
+
+ cluster.add();
+ Client c1(cluster[1]);
+ c1.session.messageTransfer(arg::content=Message("3", "k"), arg::destination="ex");
+ BOOST_CHECK_EQUAL(3, getMsgSequence(c1.subs.get("q", TIME_SEC)));
+}
+
+QPID_AUTO_TEST_CASE(testUnsupported) {
+ ScopedSuppressLogging sl;
+ ClusterFixture cluster(1);
+ Client c1(cluster[0], "c1");
+ BOOST_CHECK_THROW(c1.session.dtxSelect(), FramingErrorException);
+ Client c2(cluster[0], "c2");
+ Message m;
+ m.getDeliveryProperties().setTtl(1);
+ BOOST_CHECK_THROW(c2.session.messageTransfer(arg::content=m), Exception);
+}
+
+QPID_AUTO_TEST_CASE(testTxTransaction) {
+ ClusterFixture cluster(1);
+ Client c0(cluster[0], "c0");
+ c0.session.queueDeclare(arg::queue="q");
+ c0.session.messageTransfer(arg::content=Message("A", "q"));
+ c0.session.messageTransfer(arg::content=Message("B", "q"));
+
+ // Start a transaction that will commit.
+ Session commitSession = c0.connection.newSession("commit");
+ SubscriptionManager commitSubs(commitSession);
+ commitSession.txSelect();
+ commitSession.messageTransfer(arg::content=Message("a", "q"));
+ commitSession.messageTransfer(arg::content=Message("b", "q"));
+ BOOST_CHECK_EQUAL(commitSubs.get("q", TIME_SEC).getData(), "A");
+
+ // Start a transaction that will roll back.
+ Session rollbackSession = c0.connection.newSession("rollback");
+ SubscriptionManager rollbackSubs(rollbackSession);
+ rollbackSession.txSelect();
+ rollbackSession.messageTransfer(arg::content=Message("1", "q"));
+ Message rollbackMessage = rollbackSubs.get("q", TIME_SEC);
+ BOOST_CHECK_EQUAL(rollbackMessage.getData(), "B");
+
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("q").getMessageCount(), 0u);
+ // Add new member mid transaction.
+ cluster.add();
+ Client c1(cluster[1], "c1");
+
+ // More transactional work
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q").getMessageCount(), 0u);
+ rollbackSession.messageTransfer(arg::content=Message("2", "q"));
+ commitSession.messageTransfer(arg::content=Message("c", "q"));
+ rollbackSession.messageTransfer(arg::content=Message("3", "q"));
+
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q").getMessageCount(), 0u);
+
+ // Commit/roll back.
+ commitSession.txCommit();
+ rollbackSession.txRollback();
+ rollbackSession.messageRelease(rollbackMessage.getId());
+
+
+ // Verify queue status: just the comitted messages and dequeues should remain.
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q").getMessageCount(), 4u);
+ BOOST_CHECK_EQUAL(c1.subs.get("q", TIME_SEC).getData(), "B");
+ BOOST_CHECK_EQUAL(c1.subs.get("q", TIME_SEC).getData(), "a");
+ BOOST_CHECK_EQUAL(c1.subs.get("q", TIME_SEC).getData(), "b");
+ BOOST_CHECK_EQUAL(c1.subs.get("q", TIME_SEC).getData(), "c");
+}
+
+QPID_AUTO_TEST_CASE(testUnacked) {
+ // Verify replication of unacknowledged messages.
+ ClusterFixture cluster(1);
+ Client c0(cluster[0], "c0");
+
+ Message m;
+
+ // Create unacked message: acquired but not accepted.
+ SubscriptionSettings manualAccept(FlowControl::unlimited(), ACCEPT_MODE_EXPLICIT, ACQUIRE_MODE_PRE_ACQUIRED, 0);
+ c0.session.queueDeclare("q1");
+ c0.session.messageTransfer(arg::content=Message("11","q1"));
+ LocalQueue q1;
+ c0.subs.subscribe(q1, "q1", manualAccept);
+ BOOST_CHECK_EQUAL(q1.get(TIME_SEC).getData(), "11"); // Acquired but not accepted
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("q1").getMessageCount(), 0u); // Gone from queue
+
+ // Create unacked message: not acquired, accepted or completeed.
+ SubscriptionSettings manualAcquire(FlowControl::unlimited(), ACCEPT_MODE_EXPLICIT, ACQUIRE_MODE_NOT_ACQUIRED, 0);
+ c0.session.queueDeclare("q2");
+ c0.session.messageTransfer(arg::content=Message("21","q2"));
+ c0.session.messageTransfer(arg::content=Message("22","q2"));
+ LocalQueue q2;
+ c0.subs.subscribe(q2, "q2", manualAcquire);
+ m = q2.get(TIME_SEC); // Not acquired or accepted, still on queue
+ BOOST_CHECK_EQUAL(m.getData(), "21");
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("q2").getMessageCount(), 2u); // Not removed
+ c0.subs.getSubscription("q2").acquire(m); // Acquire manually
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("q2").getMessageCount(), 1u); // Removed
+ BOOST_CHECK_EQUAL(q2.get(TIME_SEC).getData(), "22"); // Not acquired or accepted, still on queue
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("q2").getMessageCount(), 1u); // 1 not acquired.
+
+ // Create empty credit record: acquire and accept but don't complete.
+ SubscriptionSettings manualComplete(FlowControl::messageWindow(1), ACCEPT_MODE_EXPLICIT, ACQUIRE_MODE_PRE_ACQUIRED, 1, MANUAL_COMPLETION);
+ c0.session.queueDeclare("q3");
+ c0.session.messageTransfer(arg::content=Message("31", "q3"));
+ c0.session.messageTransfer(arg::content=Message("32", "q3"));
+ LocalQueue q3;
+ c0.subs.subscribe(q3, "q3", manualComplete);
+ Message m31=q3.get(TIME_SEC);
+ BOOST_CHECK_EQUAL(m31.getData(), "31"); // Automatically acquired & accepted but not completed.
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("q3").getMessageCount(), 1u);
+
+ // Add new member while there are unacked messages.
+ cluster.add();
+ Client c1(cluster[1], "c1");
+
+ // Check queue counts
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q1").getMessageCount(), 0u);
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q2").getMessageCount(), 1u);
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q3").getMessageCount(), 1u);
+
+ // Complete the empty credit message, should unblock the message behind it.
+ BOOST_CHECK_THROW(q3.get(0), Exception);
+ c0.session.markCompleted(SequenceSet(m31.getId()), true);
+ BOOST_CHECK_EQUAL(q3.get(TIME_SEC).getData(), "32");
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("q3").getMessageCount(), 0u);
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q3").getMessageCount(), 0u);
+
+ // Close the original session - unacked messages should be requeued.
+ c0.session.close();
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q1").getMessageCount(), 1u);
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q2").getMessageCount(), 2u);
+
+ BOOST_CHECK_EQUAL(c1.subs.get("q1", TIME_SEC).getData(), "11");
+ BOOST_CHECK_EQUAL(c1.subs.get("q2", TIME_SEC).getData(), "21");
+ BOOST_CHECK_EQUAL(c1.subs.get("q2", TIME_SEC).getData(), "22");
+}
+
+QPID_AUTO_TEST_CASE_EXPECTED_FAILURES(testDumpTxState, 1) {
+ // Verify that we dump transaction state correctly to new members.
+ ClusterFixture cluster(1);
+ Client c0(cluster[0], "c0");
+
+ // Do work in a transaction.
+ c0.session.txSelect();
+ c0.session.queueDeclare("q");
+ c0.session.messageTransfer(arg::content=Message("1","q"));
+ c0.session.messageTransfer(arg::content=Message("2","q"));
+ Message m;
+ BOOST_CHECK(c0.subs.get(m, "q", TIME_SEC));
+ BOOST_CHECK_EQUAL(m.getData(), "1");
+
+ // New member, TX not comitted, c1 should see nothing.
+ cluster.add();
+ Client c1(cluster[1], "c1");
+ BOOST_CHECK_EQUAL(c1.session.queueQuery(arg::queue="q").getMessageCount(), 0u);
+
+ // After commit c1 shoudl see results of tx.
+ c0.session.txCommit();
+ BOOST_CHECK_EQUAL(c1.session.queueQuery(arg::queue="q").getMessageCount(), 1u);
+ BOOST_CHECK(c1.subs.get(m, "q", TIME_SEC));
+ BOOST_CHECK_EQUAL(m.getData(), "2");
+
+ // Another transaction with both members active.
+ c0.session.messageTransfer(arg::content=Message("3","q"));
+ BOOST_CHECK_EQUAL(c1.session.queueQuery(arg::queue="q").getMessageCount(), 0u);
+ c0.session.txCommit();
+ BOOST_CHECK_EQUAL(c1.session.queueQuery(arg::queue="q").getMessageCount(), 1u);
+ BOOST_CHECK(c1.subs.get(m, "q", TIME_SEC));
+ BOOST_CHECK_EQUAL(m.getData(), "3");
+}
+
+QPID_AUTO_TEST_CASE(testDumpMessageBuilder) {
+ // Verify that we dump a partially recieved message to a new member.
+ ClusterFixture cluster(1);
+ Client c0(cluster[0], "c0");
+ c0.session.queueDeclare("q");
+ Sender sender(ConnectionAccess::getImpl(c0.connection), c0.session.getChannel());
+
+ // Send first 2 frames of message.
+ MessageTransferBody transfer(
+ ProtocolVersion(), std::string(), // default exchange.
+ framing::message::ACCEPT_MODE_NONE,
+ framing::message::ACQUIRE_MODE_PRE_ACQUIRED);
+ sender.send(transfer, true, false, true, true);
+ AMQHeaderBody header;
+ header.get<DeliveryProperties>(true)->setRoutingKey("q");
+ sender.send(header, false, false, true, true);
+
+ // No reliable way to ensure the partial message has arrived
+ // before we start the new broker, so we sleep.
+ ::usleep(2500);
+ cluster.add();
+
+ // Send final 2 frames of message.
+ sender.send(AMQContentBody("ab"), false, true, true, false);
+ sender.send(AMQContentBody("cd"), false, true, false, true);
+
+ // Verify message is enqued correctly on second member.
+ Message m;
+ Client c1(cluster[1], "c1");
+ BOOST_CHECK(c1.subs.get(m, "q", TIME_SEC));
+ BOOST_CHECK_EQUAL(m.getData(), "abcd");
+ BOOST_CHECK_EQUAL(2u, knownBrokerPorts(c1.connection).size());
+}
+
+QPID_AUTO_TEST_CASE(testConnectionKnownHosts) {
+ ClusterFixture cluster(1);
+ Client c0(cluster[0], "c0");
+ set<uint16_t> kb0 = knownBrokerPorts(c0.connection);
+ BOOST_CHECK_EQUAL(kb0.size(), 1u);
+ BOOST_CHECK_EQUAL(kb0, makeSet(cluster));
+
+ cluster.add();
+ Client c1(cluster[1], "c1");
+ set<uint16_t> kb1 = knownBrokerPorts(c1.connection);
+ kb0 = knownBrokerPorts(c0.connection, 2);
+ BOOST_CHECK_EQUAL(kb1.size(), 2u);
+ BOOST_CHECK_EQUAL(kb1, makeSet(cluster));
+ BOOST_CHECK_EQUAL(kb1,kb0);
+
+ cluster.add();
+ Client c2(cluster[2], "c2");
+ set<uint16_t> kb2 = knownBrokerPorts(c2.connection);
+ kb1 = knownBrokerPorts(c1.connection, 3);
+ kb0 = knownBrokerPorts(c0.connection, 3);
+ BOOST_CHECK_EQUAL(kb2.size(), 3u);
+ BOOST_CHECK_EQUAL(kb2, makeSet(cluster));
+ BOOST_CHECK_EQUAL(kb2,kb0);
+ BOOST_CHECK_EQUAL(kb2,kb1);
+
+ cluster.killWithSilencer(1,c1.connection,9);
+ kb0 = knownBrokerPorts(c0.connection, 2);
+ kb2 = knownBrokerPorts(c2.connection, 2);
+ BOOST_CHECK_EQUAL(kb0.size(), 2u);
+ BOOST_CHECK_EQUAL(kb0, kb2);
+}
+
+QPID_AUTO_TEST_CASE(DumpConsumers) {
+ ClusterFixture cluster(1, 1);
+
+ Client c0(cluster[0], "c0");
+ c0.session.queueDeclare("p");
+ c0.session.queueDeclare("q");
+ c0.subs.subscribe(c0.lq, "q", FlowControl::zero());
+ LocalQueue lp;
+ c0.subs.subscribe(lp, "p", FlowControl::messageCredit(1));
+ c0.session.sync();
+
+ // Start new members
+ cluster.add(); // Local
+ Client c1(cluster[1], "c1");
+ cluster.add();
+ Client c2(cluster[2], "c2");
+
+ // Transfer messages
+ c0.session.messageTransfer(arg::content=Message("aaa", "q"));
+
+ c0.session.messageTransfer(arg::content=Message("bbb", "p"));
+ c0.session.messageTransfer(arg::content=Message("ccc", "p"));
+
+ // Activate the subscription, ensure message removed on all queues.
+ c0.subs.setFlowControl("q", FlowControl::unlimited());
+ Message m;
+ BOOST_CHECK(c0.lq.get(m, TIME_SEC));
+ BOOST_CHECK_EQUAL(m.getData(), "aaa");
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("q").getMessageCount(), 0u);
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q").getMessageCount(), 0u);
+ BOOST_CHECK_EQUAL(c2.session.queueQuery("q").getMessageCount(), 0u);
+
+ // Check second subscription's flow control: gets first message, not second.
+ BOOST_CHECK(lp.get(m, TIME_SEC));
+ BOOST_CHECK_EQUAL(m.getData(), "bbb");
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("p").getMessageCount(), 1u);
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("p").getMessageCount(), 1u);
+ BOOST_CHECK_EQUAL(c2.session.queueQuery("p").getMessageCount(), 1u);
+
+ BOOST_CHECK(c0.subs.get(m, "p", TIME_SEC));
+ BOOST_CHECK_EQUAL(m.getData(), "ccc");
+
+ // Kill the subscribing member, ensure further messages are not removed.
+ cluster.killWithSilencer(0,c0.connection,9);
+ BOOST_REQUIRE_EQUAL(knownBrokerPorts(c1.connection, 2).size(), 2u);
+ for (int i = 0; i < 10; ++i) {
+ c1.session.messageTransfer(arg::content=Message("xxx", "q"));
+ BOOST_REQUIRE(c1.subs.get(m, "q", TIME_SEC));
+ BOOST_REQUIRE_EQUAL(m.getData(), "xxx");
+ }
+}
+
+QPID_AUTO_TEST_CASE(testCatchupSharedState) {
+ ClusterFixture cluster(1);
+ Client c0(cluster[0], "c0");
+
+ // Create some shared state.
+ c0.session.queueDeclare("q");
+ c0.session.messageTransfer(arg::content=Message("foo","q"));
+ c0.session.messageTransfer(arg::content=Message("bar","q"));
+ while (c0.session.queueQuery("q").getMessageCount() != 2)
+ ::usleep(1000); // Wait for message to show up on broker 0.
+
+ // Add a new broker, it should catch up.
+ cluster.add();
+
+ // Do some work post-add
+ c0.session.queueDeclare("p");
+ c0.session.messageTransfer(arg::content=Message("pfoo","p"));
+
+ // Do some work post-join
+ BOOST_REQUIRE_EQUAL(knownBrokerPorts(c0.connection, 2).size(), 2u);
+ c0.session.messageTransfer(arg::content=Message("pbar","p"));
+
+ // Verify new brokers have state.
+ Message m;
+
+ Client c1(cluster[1], "c1");
+
+ BOOST_CHECK(c1.subs.get(m, "q", TIME_SEC));
+ BOOST_CHECK_EQUAL(m.getData(), "foo");
+ BOOST_CHECK(c1.subs.get(m, "q", TIME_SEC));
+ BOOST_CHECK_EQUAL(m.getData(), "bar");
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q").getMessageCount(), 0u);
+
+ // Add another broker, don't wait for join - should be stalled till ready.
+ cluster.add();
+ Client c2(cluster[2], "c2");
+ BOOST_CHECK(c2.subs.get(m, "p", TIME_SEC));
+ BOOST_CHECK_EQUAL(m.getData(), "pfoo");
+ BOOST_CHECK(c2.subs.get(m, "p", TIME_SEC));
+ BOOST_CHECK_EQUAL(m.getData(), "pbar");
+ BOOST_CHECK_EQUAL(c2.session.queueQuery("p").getMessageCount(), 0u);
+}
+
+QPID_AUTO_TEST_CASE(testWiringReplication) {
+ ClusterFixture cluster(3);
+ Client c0(cluster[0]);
+ BOOST_CHECK(c0.session.queueQuery("q").getQueue().empty());
+ BOOST_CHECK(c0.session.exchangeQuery("ex").getType().empty());
+ c0.session.queueDeclare("q");
+ c0.session.exchangeDeclare("ex", arg::type="direct");
+ c0.session.close();
+ c0.connection.close();
+ // Verify all brokers get wiring update.
+ for (size_t i = 0; i < cluster.size(); ++i) {
+ BOOST_MESSAGE("i == "<< i);
+ Client c(cluster[i]);
+ BOOST_CHECK_EQUAL("q", c.session.queueQuery("q").getQueue());
+ BOOST_CHECK_EQUAL("direct", c.session.exchangeQuery("ex").getType());
+ }
+}
+
+QPID_AUTO_TEST_CASE(testMessageEnqueue) {
+ // Enqueue on one broker, dequeue on another.
+ ClusterFixture cluster(2);
+ Client c0(cluster[0]);
+ c0.session.queueDeclare("q");
+ c0.session.messageTransfer(arg::content=Message("foo", "q"));
+ c0.session.messageTransfer(arg::content=Message("bar", "q"));
+ c0.session.close();
+ Client c1(cluster[1]);
+ Message msg;
+ BOOST_CHECK(c1.subs.get(msg, "q", qpid::sys::TIME_SEC));
+ BOOST_CHECK_EQUAL(string("foo"), msg.getData());
+ BOOST_CHECK(c1.subs.get(msg, "q", qpid::sys::TIME_SEC));
+ BOOST_CHECK_EQUAL(string("bar"), msg.getData());
+}
+
+QPID_AUTO_TEST_CASE(testMessageDequeue) {
+ // Enqueue on one broker, dequeue on two others.
+ ClusterFixture cluster(3);
+ Client c0(cluster[0], "c0");
+ c0.session.queueDeclare("q");
+ c0.session.messageTransfer(arg::content=Message("foo", "q"));
+ c0.session.messageTransfer(arg::content=Message("bar", "q"));
+
+ Message msg;
+
+ // Dequeue on 2 others, ensure correct order.
+ Client c1(cluster[1], "c1");
+ BOOST_CHECK(c1.subs.get(msg, "q"));
+ BOOST_CHECK_EQUAL("foo", msg.getData());
+
+ Client c2(cluster[2], "c2");
+ BOOST_CHECK(c1.subs.get(msg, "q"));
+ BOOST_CHECK_EQUAL("bar", msg.getData());
+
+ // Queue should be empty on all cluster members.
+ BOOST_CHECK_EQUAL(0u, c0.session.queueQuery("q").getMessageCount());
+ BOOST_CHECK_EQUAL(0u, c1.session.queueQuery("q").getMessageCount());
+ BOOST_CHECK_EQUAL(0u, c2.session.queueQuery("q").getMessageCount());
+}
+
+QPID_AUTO_TEST_CASE(testDequeueWaitingSubscription) {
+ ClusterFixture cluster(3);
+ Client c0(cluster[0]);
+ BOOST_REQUIRE_EQUAL(knownBrokerPorts(c0.connection, 3).size(), 3u); // Wait for brokers.
+
+ // First start a subscription.
+ c0.session.queueDeclare("q");
+ c0.subs.subscribe(c0.lq, "q", FlowControl::messageCredit(2));
+
+ // Now send messages
+ Client c1(cluster[1]);
+ c1.session.messageTransfer(arg::content=Message("foo", "q"));
+ c1.session.messageTransfer(arg::content=Message("bar", "q"));
+
+ // Check they arrived
+ Message m;
+ BOOST_CHECK(c0.lq.get(m, sys::TIME_SEC));
+ BOOST_CHECK_EQUAL("foo", m.getData());
+ BOOST_CHECK(c0.lq.get(m, sys::TIME_SEC));
+ BOOST_CHECK_EQUAL("bar", m.getData());
+
+ // Queue should be empty on all cluster members.
+ Client c2(cluster[2]);
+ BOOST_CHECK_EQUAL(0u, c0.session.queueQuery("q").getMessageCount());
+ BOOST_CHECK_EQUAL(0u, c1.session.queueQuery("q").getMessageCount());
+ BOOST_CHECK_EQUAL(0u, c2.session.queueQuery("q").getMessageCount());
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/config.null b/RC9/qpid/cpp/src/tests/config.null
new file mode 100644
index 0000000000..565c7da435
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/config.null
@@ -0,0 +1 @@
+# empty config
diff --git a/RC9/qpid/cpp/src/tests/consume.cpp b/RC9/qpid/cpp/src/tests/consume.cpp
new file mode 100644
index 0000000000..4d74b8ae57
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/consume.cpp
@@ -0,0 +1,119 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <algorithm>
+#include <iostream>
+#include <memory>
+#include <sstream>
+#include <vector>
+
+#include "TestOptions.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/Session.h"
+#include "qpid/client/SubscriptionManager.h"
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace qpid::sys;
+using namespace std;
+
+typedef vector<string> StringSet;
+
+struct Args : public qpid::TestOptions {
+ uint count;
+ uint ack;
+ string queue;
+ bool declare;
+ bool summary;
+
+ Args() : count(1000), ack(0), queue("publish-consume"),
+ declare(false), summary(false)
+ {
+ addOptions()
+ ("count", optValue(count, "N"), "number of messages to publish")
+ ("ack-frequency", optValue(ack, "N"), "ack every N messages (0 means use no-ack mode)")
+ ("queue", optValue(queue, "<queue name>"), "queue to consume from")
+ ("declare", optValue(declare), "declare the queue")
+ ("s,summary", optValue(summary), "Print undecorated rate.");
+ }
+};
+
+Args opts;
+
+struct Client
+{
+ Connection connection;
+ Session session;
+
+ Client()
+ {
+ opts.open(connection);
+ session = connection.newSession();
+ }
+
+ void consume()
+ {
+ if (opts.declare)
+ session.queueDeclare(opts.queue);
+ SubscriptionManager subs(session);
+ LocalQueue lq;
+ SubscriptionSettings settings;
+ settings.acceptMode = opts.ack > 0 ? ACCEPT_MODE_EXPLICIT : ACCEPT_MODE_NONE;
+ settings.flowControl = FlowControl(opts.count, SubscriptionManager::UNLIMITED,false);
+ Subscription sub = subs.subscribe(lq, opts.queue, settings);
+ Message msg;
+ AbsTime begin=now();
+ for (size_t i = 0; i < opts.count; ++i) {
+ msg=lq.pop();
+ QPID_LOG(info, "Received: " << msg.getMessageProperties().getCorrelationId());
+ }
+ if (opts.ack != 0)
+ sub.accept(sub.getUnaccepted()); // Cumulative ack for final batch.
+ AbsTime end=now();
+ double secs(double(Duration(begin,end))/TIME_SEC);
+ if (opts.summary) cout << opts.count/secs << endl;
+ else cout << "Time: " << secs << "s Rate: " << opts.count/secs << endl;
+ }
+
+ ~Client()
+ {
+ try{
+ session.close();
+ connection.close();
+ } catch(const exception& e) {
+ cout << e.what() << endl;
+ }
+ }
+};
+
+int main(int argc, char** argv)
+{
+ try {
+ opts.parse(argc, argv);
+ Client client;
+ client.consume();
+ return 0;
+ } catch(const exception& e) {
+ cout << e.what() << endl;
+ }
+ return 1;
+}
diff --git a/RC9/qpid/cpp/src/tests/declare_queues.cpp b/RC9/qpid/cpp/src/tests/declare_queues.cpp
new file mode 100644
index 0000000000..7f61bde12a
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/declare_queues.cpp
@@ -0,0 +1,69 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/client/FailoverManager.h>
+#include <qpid/client/Session.h>
+#include <qpid/Exception.h>
+
+#include <cstdlib>
+#include <iostream>
+
+using namespace qpid::client;
+
+using namespace std;
+
+int main(int argc, char ** argv)
+{
+ ConnectionSettings settings;
+ if ( argc != 3 )
+ {
+ cerr << "Usage: declare_queues host port\n";
+ return 1;
+ }
+
+ settings.host = argv[1];
+ settings.port = atoi(argv[2]);
+
+ FailoverManager connection(settings);
+ try {
+ bool complete = false;
+ while (!complete) {
+ Session session = connection.connect().newSession();
+ try {
+ session.queueDeclare(arg::queue="message_queue");
+ complete = true;
+ } catch (const qpid::TransportFailure&) {}
+ }
+ connection.close();
+ return 0;
+ } catch (const exception& error) {
+ cerr << "declare_queues failed:" << error.what() << endl;
+ cerr << " host: " << settings.host
+ << " port: " << settings.port << endl;
+ return 1;
+ }
+
+}
+
+
+
+
+
diff --git a/RC9/qpid/cpp/src/tests/dlclose_noop.c b/RC9/qpid/cpp/src/tests/dlclose_noop.c
new file mode 100644
index 0000000000..ba2fa75891
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/dlclose_noop.c
@@ -0,0 +1,30 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/*
+ * Loaded via LD_PRELOAD this will turn dlclose into a no-op.
+ *
+ * Allows valgrind to generate useful reports from programs that
+ * dynamically unload libraries before exit, such as CppUnit's
+ * DllPlugInTester.
+ *
+ */
+
+#include <stdio.h>
+void* dlclose(void* handle) {}
+
diff --git a/RC9/qpid/cpp/src/tests/echotest.cpp b/RC9/qpid/cpp/src/tests/echotest.cpp
new file mode 100644
index 0000000000..7cbf3e7df4
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/echotest.cpp
@@ -0,0 +1,150 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/client/Connection.h>
+#include <qpid/client/SubscriptionManager.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/Message.h>
+#include <qpid/client/MessageListener.h>
+#include <qpid/sys/Time.h>
+
+#include <iostream>
+
+using namespace qpid::client;
+using namespace qpid::framing;
+using namespace qpid::sys;
+using namespace std;
+
+struct Args : public qpid::Options,
+ public qpid::client::ConnectionSettings
+{
+ bool help;
+ uint count;
+ uint size;
+ bool summary;
+
+ Args() : qpid::Options("Simple latency test optins"), help(false), count(20), size(0), summary()
+ {
+ using namespace qpid;
+ addOptions()
+ ("help", optValue(help), "Print this usage statement")
+ ("count", optValue(count, "N"), "Number of messages to send")
+ ("size", optValue(count, "N"), "Size of messages")
+ ("broker,b", optValue(host, "HOST"), "Broker host to connect to")
+ ("port,p", optValue(port, "PORT"), "Broker port to connect to")
+ ("username", optValue(username, "USER"), "user name for broker log in.")
+ ("password", optValue(password, "PASSWORD"), "password for broker log in.")
+ ("mechanism", optValue(mechanism, "MECH"), "SASL mechanism to use when authenticating.")
+ ("tcp-nodelay", optValue(tcpNoDelay), "Turn on tcp-nodelay")
+ ("s,summary", optValue(summary), "Print only average latency.");
+ }
+};
+
+uint64_t current_time()
+{
+ Duration t(now());
+ return t;
+}
+
+class Listener : public MessageListener
+{
+ private:
+ Session session;
+ SubscriptionManager subscriptions;
+ uint counter;
+ const uint limit;
+ std::string queue;
+ Message request;
+ double total, min, max;
+ bool summary;
+
+ public:
+ Listener(Session& session, uint limit, bool summary);
+ void start(uint size);
+ void received(Message& message);
+};
+
+Listener::Listener(Session& s, uint l, bool summary_) :
+ session(s), subscriptions(s), counter(0), limit(l),
+ queue(session.getId().getName()), total(),
+ min(std::numeric_limits<double>::max()), max(), summary(summary_)
+{}
+
+void Listener::start(uint size)
+{
+ session.queueDeclare(arg::queue=queue, arg::exclusive=true, arg::autoDelete=true);
+ request.getDeliveryProperties().setRoutingKey(queue);
+ subscriptions.subscribe(*this, queue, SubscriptionSettings(FlowControl::unlimited(), ACCEPT_MODE_NONE));
+
+ request.getDeliveryProperties().setTimestamp(current_time());
+ if (size) request.setData(std::string(size, 'X'));
+ async(session).messageTransfer(arg::content=request);
+ subscriptions.run();
+}
+
+void Listener::received(Message& response)
+{
+ //extract timestamp and compute latency:
+ uint64_t sentAt = response.getDeliveryProperties().getTimestamp();
+ uint64_t receivedAt = current_time();
+
+ double latency = ((double) (receivedAt - sentAt)) / TIME_MSEC;
+ if (!summary) cout << "Latency: " << latency << "ms" << endl;
+ min = std::min(latency, min);
+ max = std::max(latency, max);
+ total += latency;
+
+ if (++counter < limit) {
+ request.getDeliveryProperties().setTimestamp(current_time());
+ async(session).messageTransfer(arg::content=request);
+ } else {
+ subscriptions.cancel(queue);
+ if (summary) cout << min << "\t" << max << "\t" << total/limit << endl;
+ else cout << "min: " << min << " max: " << max << " average: " << total/limit << endl;
+ }
+}
+
+int main(int argc, char** argv)
+{
+ Args opts;
+ opts.parse(argc, argv);
+
+ if (opts.help) {
+ std::cout << opts << std::endl;
+ return 0;
+ }
+
+ Connection connection;
+ try {
+ connection.open(opts);
+ Session session = connection.newSession();
+ Listener listener(session, opts.count, opts.summary);
+ listener.start(opts.size);
+
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/RC9/qpid/cpp/src/tests/exception_test.cpp b/RC9/qpid/cpp/src/tests/exception_test.cpp
new file mode 100644
index 0000000000..e420bf2f0b
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/exception_test.cpp
@@ -0,0 +1,121 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "unit_test.h"
+#include "test_tools.h"
+#include "BrokerFixture.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/sys/Thread.h"
+#include "qpid/framing/reply_exceptions.h"
+
+QPID_AUTO_TEST_SUITE(exception_test)
+
+// FIXME aconway 2008-06-12: need to update our exception handling to
+// 0-10 handling and extend this test to provoke all the exceptional
+// conditions we know of and verify the correct exception is thrown.
+
+using namespace std;
+using namespace qpid;
+using namespace sys;
+using namespace client;
+using namespace framing;
+
+using qpid::broker::Broker;
+using boost::bind;
+using boost::function;
+
+template <class Ex>
+struct Catcher : public Runnable {
+ function<void ()> f;
+ bool caught;
+ Thread thread;
+
+ Catcher(function<void ()> f_) : f(f_), caught(false), thread(this) {}
+ ~Catcher() { join(); }
+
+ void run() {
+ try {
+ ScopedSuppressLogging sl; // Suppress messages for expected errors.
+ f();
+ }
+ catch(const Ex& e) {
+ caught=true;
+ BOOST_MESSAGE(string("Caught expected exception: ")+e.what()+"["+typeid(e).name()+"]");
+ }
+ catch(const std::exception& e) {
+ BOOST_ERROR(string("Bad exception: ")+e.what()+"["+typeid(e).name()+"] expected: "+typeid(Ex).name());
+ }
+ catch(...) {
+ BOOST_ERROR(string("Bad exception: unknown"));
+ }
+ }
+
+ bool join() {
+ if (thread.id()) {
+ thread.join();
+ thread=Thread();
+ }
+ return caught;
+ }
+};
+
+QPID_AUTO_TEST_CASE(TestSessionBusy) {
+ SessionFixture f;
+ try {
+ ScopedSuppressLogging sl; // Suppress messages for expected errors.
+ f.connection.newSession(f.session.getId().getName());
+ BOOST_FAIL("Expected SessionBusyException for " << f.session.getId().getName());
+ } catch (const SessionBusyException&) {} // FIXME aconway 2008-09-22: client is not throwing correct exception.
+}
+
+QPID_AUTO_TEST_CASE(DisconnectedPop) {
+ ProxySessionFixture fix;
+ ProxyConnection c(fix.broker->getPort(Broker::TCP_TRANSPORT));
+ fix.session.queueDeclare(arg::queue="q");
+ fix.subs.subscribe(fix.lq, "q");
+ Catcher<TransportFailure> pop(bind(&LocalQueue::pop, &fix.lq, sys::TIME_SEC));
+ fix.connection.proxy.close();
+ BOOST_CHECK(pop.join());
+}
+
+QPID_AUTO_TEST_CASE(DisconnectedListen) {
+ ProxySessionFixture fix;
+ struct NullListener : public MessageListener {
+ void received(Message&) { BOOST_FAIL("Unexpected message"); }
+ } l;
+ ProxyConnection c(fix.broker->getPort(Broker::TCP_TRANSPORT));
+ fix.session.queueDeclare(arg::queue="q");
+ fix.subs.subscribe(l, "q");
+
+ Catcher<TransportFailure> runner(bind(&SubscriptionManager::run, boost::ref(fix.subs)));
+ fix.connection.proxy.close();
+ runner.join();
+ BOOST_CHECK_THROW(fix.session.close(), TransportFailure);
+}
+
+QPID_AUTO_TEST_CASE(NoSuchQueueTest) {
+ ProxySessionFixture fix;
+ ScopedSuppressLogging sl; // Suppress messages for expected errors.
+ BOOST_CHECK_THROW(fix.subs.subscribe(fix.lq, "no such queue"), NotFoundException);
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/failover_soak.cpp b/RC9/qpid/cpp/src/tests/failover_soak.cpp
new file mode 100644
index 0000000000..6149e845e4
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/failover_soak.cpp
@@ -0,0 +1,654 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <string.h>
+
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <vector>
+
+#include <ForkedBroker.h>
+
+
+
+
+using namespace std;
+
+
+typedef vector<ForkedBroker *> brokerVector;
+
+typedef enum
+{
+ NO_STATUS,
+ RUNNING,
+ COMPLETED
+}
+childStatus;
+
+
+
+struct child
+{
+ child ( string & name, pid_t pid )
+ : name(name), pid(pid), retval(-999), status(RUNNING)
+ {
+ gettimeofday ( & startTime, 0 );
+ }
+
+
+ void
+ done ( int _retval )
+ {
+ retval = _retval;
+ status = COMPLETED;
+ gettimeofday ( & stopTime, 0 );
+ }
+
+
+ string name;
+ pid_t pid;
+ int retval;
+ childStatus status;
+ struct timeval startTime,
+ stopTime;
+};
+
+
+
+
+struct children : public vector<child *>
+{
+ void
+ add ( string & name, pid_t pid )
+ {
+ push_back(new child ( name, pid ));
+ }
+
+
+ child *
+ get ( pid_t pid )
+ {
+ vector<child *>::iterator i;
+ for ( i = begin(); i != end(); ++ i )
+ if ( pid == (*i)->pid )
+ return *i;
+
+ return 0;
+ }
+
+
+ void
+ exited ( pid_t pid, int retval )
+ {
+ child * kid = get ( pid );
+ if(! kid)
+ {
+ if ( verbosity > 0 )
+ {
+ cerr << "children::exited warning: Can't find child with pid "
+ << pid
+ << endl;
+ }
+ return;
+ }
+
+ kid->done ( retval );
+ }
+
+
+ int
+ unfinished ( )
+ {
+ int count = 0;
+
+ vector<child *>::iterator i;
+ for ( i = begin(); i != end(); ++ i )
+ if ( COMPLETED != (*i)->status )
+ ++ count;
+
+ return count;
+ }
+
+
+ int
+ checkChildren ( )
+ {
+ vector<child *>::iterator i;
+ for ( i = begin(); i != end(); ++ i )
+ if ( (COMPLETED == (*i)->status) && (0 != (*i)->retval) )
+ return (*i)->retval;
+
+ return 0;
+ }
+
+
+ void
+ killEverybody ( )
+ {
+ vector<child *>::iterator i;
+ for ( i = begin(); i != end(); ++ i )
+ kill ( (*i)->pid, 9 );
+ }
+
+
+
+ void
+ print ( )
+ {
+ cout << "--- status of all children --------------\n";
+ vector<child *>::iterator i;
+ for ( i = begin(); i != end(); ++ i )
+ cout << "child: " << (*i)->name
+ << " status: " << (*i)->status
+ << endl;
+ cout << "\n\n\n\n";
+ }
+
+
+ /*
+ Only call this if you already know there is at least
+ one child still running. Supply a time in seconds.
+ If it has been at least that long since a shild stopped
+ running, we judge the system to have hung.
+ */
+ bool
+ hanging ( int hangTime )
+ {
+ struct timeval now,
+ duration;
+ gettimeofday ( &now, 0 );
+
+ vector<child *>::iterator i;
+ for ( i = begin(); i != end(); ++ i )
+ {
+ timersub ( & now, &((*i)->startTime), & duration );
+ if ( duration.tv_sec >= hangTime )
+ return true;
+ }
+
+ return false;
+ }
+
+
+ int verbosity;
+};
+
+
+
+children allMyChildren;
+
+
+
+
+void
+childExit ( int signalNumber )
+{
+ signalNumber ++; // Now maybe the compiler willleave me alone?
+ int childReturnCode;
+ pid_t pid = waitpid ( 0, & childReturnCode, WNOHANG);
+
+ if ( pid > 0 )
+ allMyChildren.exited ( pid, childReturnCode );
+}
+
+
+
+int
+mrand ( int maxDesiredVal ) {
+ double zeroToOne = (double) rand() / (double) RAND_MAX;
+ return (int) (zeroToOne * (double) maxDesiredVal);
+}
+
+
+
+int
+mrand ( int minDesiredVal, int maxDesiredVal ) {
+ int interval = maxDesiredVal - minDesiredVal;
+ return minDesiredVal + mrand ( interval );
+}
+
+
+
+void
+makeClusterName ( string & s, int & num ) {
+ num = mrand(1000);
+ stringstream ss;
+ ss << "soakTestCluster_" << num;
+ s = ss.str();
+}
+
+
+
+
+
+void
+printBrokers ( brokerVector & brokers )
+{
+ cout << "Broker List ------------ size: " << brokers.size() << "\n";
+ for ( brokerVector::iterator i = brokers.begin(); i != brokers.end(); ++ i) {
+ cout << "pid: "
+ << (*i)->getPID()
+ << " port: "
+ << (*i)->getPort()
+ << endl;
+ }
+ cout << "end Broker List ------------\n";
+}
+
+
+
+
+
+void
+startNewBroker ( brokerVector & brokers,
+ char const * srcRoot,
+ char const * moduleDir,
+ string const clusterName )
+{
+ static int brokerId = 0;
+ stringstream path, prefix, module;
+ module << moduleDir << "/cluster.so";
+ path << srcRoot << "/qpidd";
+ prefix << "soak-" << brokerId++;
+
+ const char * const argv[] =
+ {
+ "qpidd",
+ "-p0",
+ "--load-module=cluster.so",
+ "--cluster-name",
+ clusterName.c_str(),
+ "--auth=no",
+ "--no-data-dir",
+ "--no-module-dir",
+ "--mgmt-enable=no",
+ "--log-prefix", prefix.str().c_str(),
+ 0
+ };
+
+ size_t argc = sizeof(argv)/sizeof(argv[0]);
+ brokers.push_back ( new ForkedBroker ( argc, argv ) );
+}
+
+
+
+
+
+void
+killFrontBroker ( brokerVector & brokers, int verbosity )
+{
+ if ( verbosity > 0 )
+ cout << "killFrontBroker pid: " << brokers[0]->getPID() << " on port " << brokers[0]->getPort() << endl;
+ try { brokers[0]->kill(9); }
+ catch ( const exception& error ) {
+ if ( verbosity > 0 )
+ cout << "error killing broker: " << error.what() << endl;
+ }
+ delete brokers[0];
+ brokers.erase ( brokers.begin() );
+}
+
+
+
+
+
+void
+killAllBrokers ( brokerVector & brokers )
+{
+ for ( uint i = 0; i < brokers.size(); ++ i )
+ try { brokers[i]->kill(9); }
+ catch ( ... ) { }
+}
+
+
+
+
+
+pid_t
+runDeclareQueuesClient ( brokerVector brokers,
+ char const * host,
+ char const * path,
+ int verbosity
+ )
+{
+ string name("declareQueues");
+ int port = brokers[0]->getPort ( );
+
+ if ( verbosity > 0 )
+ cout << "startDeclareQueuesClient: host: "
+ << host
+ << " port: "
+ << port
+ << endl;
+ stringstream portSs;
+ portSs << port;
+
+ vector<const char*> argv;
+ argv.push_back ( "declareQueues" );
+ argv.push_back ( host );
+ argv.push_back ( portSs.str().c_str() );
+ argv.push_back ( 0 );
+ pid_t pid = fork();
+
+ if ( ! pid ) {
+ execv ( path, const_cast<char * const *>(&argv[0]) );
+ perror ( "error executing dq: " );
+ return 0;
+ }
+
+ allMyChildren.add ( name, pid );
+ return pid;
+}
+
+
+
+
+
+pid_t
+startReceivingClient ( brokerVector brokers,
+ char const * host,
+ char const * receiverPath,
+ char const * reportFrequency,
+ int verbosity
+ )
+{
+ string name("receiver");
+ int port = brokers[0]->getPort ( );
+
+ if ( verbosity > 0 )
+ cout << "startReceivingClient: port " << port << endl;
+ char portStr[100];
+ char verbosityStr[100];
+ sprintf(portStr, "%d", port);
+ sprintf(verbosityStr, "%d", verbosity);
+
+
+ vector<const char*> argv;
+ argv.push_back ( "resumingReceiver" );
+ argv.push_back ( host );
+ argv.push_back ( portStr );
+ argv.push_back ( reportFrequency );
+ argv.push_back ( verbosityStr );
+ argv.push_back ( 0 );
+
+ pid_t pid = fork();
+
+ if ( ! pid ) {
+ execv ( receiverPath, const_cast<char * const *>(&argv[0]) );
+ perror ( "error executing receiver: " );
+ return 0;
+ }
+
+ allMyChildren.add ( name, pid );
+ return pid;
+}
+
+
+
+
+
+pid_t
+startSendingClient ( brokerVector brokers,
+ char const * host,
+ char const * senderPath,
+ char const * nMessages,
+ char const * reportFrequency,
+ int verbosity
+ )
+{
+ string name("sender");
+ int port = brokers[0]->getPort ( );
+
+ if ( verbosity )
+ cout << "startSenderClient: port " << port << endl;
+ char portStr[100];
+ char verbosityStr[100];
+
+ sprintf ( portStr, "%d", port);
+ sprintf ( verbosityStr, "%d", verbosity);
+
+ vector<const char*> argv;
+ argv.push_back ( "replayingSender" );
+ argv.push_back ( host );
+ argv.push_back ( portStr );
+ argv.push_back ( nMessages );
+ argv.push_back ( reportFrequency );
+ argv.push_back ( verbosityStr );
+ argv.push_back ( 0 );
+
+ pid_t pid = fork();
+
+ if ( ! pid ) {
+ execv ( senderPath, const_cast<char * const *>(&argv[0]) );
+ perror ( "error executing sender: " );
+ return 0;
+ }
+
+ allMyChildren.add ( name, pid );
+ return pid;
+}
+
+
+
+#define HUNKY_DORY 0
+#define BAD_ARGS 1
+#define CANT_FORK_DQ 2
+#define CANT_FORK_RECEIVER 3
+#define DQ_FAILED 4
+#define ERROR_ON_CHILD 5
+#define HANGING 6
+
+
+int
+main ( int argc, char const ** argv )
+{
+ if ( argc < 9 ) {
+ cerr << "Usage: failoverSoak srcRoot moduleDir host senderPath receiverPath nMessages verbosity\n";
+ cerr << " ( argc was " << argc << " )\n";
+ return BAD_ARGS;
+ }
+
+ signal ( SIGCHLD, childExit );
+
+ char const * srcRoot = argv[1];
+ char const * moduleDir = argv[2];
+ char const * host = argv[3];
+ char const * declareQueuesPath = argv[4];
+ char const * senderPath = argv[5];
+ char const * receiverPath = argv[6];
+ char const * nMessages = argv[7];
+ char const * reportFrequency = argv[8];
+ int verbosity = atoi(argv[9]);
+
+ int maxBrokers = 50;
+
+ allMyChildren.verbosity = verbosity;
+
+ int clusterNum;
+ string clusterName;
+
+ srand ( getpid() );
+
+ makeClusterName ( clusterName, clusterNum );
+
+ brokerVector brokers;
+
+ if ( verbosity > 0 )
+ cout << "Starting initial cluster...\n";
+
+ int nBrokers = 3;
+ for ( int i = 0; i < nBrokers; ++ i ) {
+ startNewBroker ( brokers,
+ srcRoot,
+ moduleDir,
+ clusterName );
+ }
+
+
+ if ( verbosity > 0 )
+ printBrokers ( brokers );
+
+ // Run the declareQueues child.
+ int childStatus;
+ pid_t dqClientPid =
+ runDeclareQueuesClient ( brokers, host, declareQueuesPath, verbosity );
+ if ( -1 == dqClientPid ) {
+ cerr << "failoverSoak error: Couldn't fork declareQueues.\n";
+ return CANT_FORK_DQ;
+ }
+
+ // Don't continue until declareQueues is finished.
+ pid_t retval = waitpid ( dqClientPid, & childStatus, 0);
+ if ( retval != dqClientPid) {
+ cerr << "failoverSoak error: waitpid on declareQueues returned value " << retval << endl;
+ return DQ_FAILED;
+ }
+ allMyChildren.exited ( dqClientPid, childStatus );
+
+
+
+ // Start the receiving client.
+ pid_t receivingClientPid =
+ startReceivingClient ( brokers,
+ host,
+ receiverPath,
+ reportFrequency,
+ verbosity );
+ if ( -1 == receivingClientPid ) {
+ cerr << "failoverSoak error: Couldn't fork receiver.\n";
+ return CANT_FORK_RECEIVER;
+ }
+
+
+ // Start the sending client.
+ pid_t sendingClientPid =
+ startSendingClient ( brokers,
+ host,
+ senderPath,
+ nMessages,
+ reportFrequency,
+ verbosity );
+ if ( -1 == sendingClientPid ) {
+ cerr << "failoverSoak error: Couldn't fork sender.\n";
+ return CANT_FORK_RECEIVER;
+ }
+
+
+ int minSleep = 3,
+ maxSleep = 6;
+
+
+ for ( int totalBrokers = 3;
+ totalBrokers < maxBrokers;
+ ++ totalBrokers
+ )
+ {
+ if ( verbosity > 0 )
+ cout << totalBrokers << " brokers have been added to the cluster.\n\n\n";
+
+ // Sleep for a while. -------------------------
+ int sleepyTime = mrand ( minSleep, maxSleep );
+ if ( verbosity > 0 )
+ cout << "Sleeping for " << sleepyTime << " seconds.\n";
+ sleep ( sleepyTime );
+
+ // Kill the oldest broker. --------------------------
+ killFrontBroker ( brokers, verbosity );
+
+ // Sleep for a while. -------------------------
+ sleepyTime = mrand ( minSleep, maxSleep );
+ if ( verbosity > 0 )
+ cerr << "Sleeping for " << sleepyTime << " seconds.\n";
+ sleep ( sleepyTime );
+
+ // Start a new broker. --------------------------
+ if ( verbosity > 0 )
+ cout << "Starting new broker.\n\n";
+
+ startNewBroker ( brokers,
+ srcRoot,
+ moduleDir,
+ clusterName );
+
+ if ( verbosity > 0 )
+ printBrokers ( brokers );
+
+ // If all children have exited, quit.
+ int unfinished = allMyChildren.unfinished();
+ if ( ! unfinished ) {
+ killAllBrokers ( brokers );
+
+ if ( verbosity > 0 )
+ cout << "failoverSoak: all children have exited.\n";
+ int retval = allMyChildren.checkChildren();
+ if ( verbosity > 0 )
+ std::cerr << "failoverSoak: checkChildren: " << retval << endl;
+ return retval ? ERROR_ON_CHILD : HUNKY_DORY;
+ }
+
+ // Even if some are still running, if there's an error, quit.
+ if ( allMyChildren.checkChildren() )
+ {
+ if ( verbosity > 0 )
+ cout << "failoverSoak: error on child.\n";
+ allMyChildren.killEverybody();
+ killAllBrokers ( brokers );
+ return ERROR_ON_CHILD;
+ }
+
+ // If one is hanging, quit.
+ if ( allMyChildren.hanging ( 120 ) )
+ {
+ if ( verbosity > 0 )
+ cout << "failoverSoak: child hanging.\n";
+ allMyChildren.killEverybody();
+ killAllBrokers ( brokers );
+ return HANGING;
+ }
+
+ if ( verbosity > 0 ) {
+ std::cerr << "------- next kill-broker loop --------\n";
+ allMyChildren.print();
+ }
+ }
+
+ retval = allMyChildren.checkChildren();
+ if ( verbosity > 0 )
+ std::cerr << "failoverSoak: checkChildren: " << retval << endl;
+
+ if ( verbosity > 0 )
+ cout << "failoverSoak: maxBrokers reached.\n";
+
+ allMyChildren.killEverybody();
+ killAllBrokers ( brokers );
+
+ return retval ? ERROR_ON_CHILD : HUNKY_DORY;
+}
+
+
+
diff --git a/RC9/qpid/cpp/src/tests/fanout_perftest b/RC9/qpid/cpp/src/tests/fanout_perftest
new file mode 100755
index 0000000000..d8a7661f49
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/fanout_perftest
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+exec `dirname $0`/run_perftest 10000 --mode fanout --npubs 16 --nsubs 16 --size 64
diff --git a/RC9/qpid/cpp/src/tests/federated_topic_test b/RC9/qpid/cpp/src/tests/federated_topic_test
new file mode 100755
index 0000000000..21d8411eaf
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/federated_topic_test
@@ -0,0 +1,130 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Run the topic test on a federated setup
+
+# Clean up old log files
+rm -f subscriber_*.log
+
+# Defaults values
+SUBSCRIBERS=2
+MESSAGES=1000
+BATCHES=1
+VERBOSE=1
+
+while getopts "s:m:b:" opt ; do
+ case $opt in
+ s) SUBSCRIBERS=$OPTARG ;;
+ m) MESSAGES=$OPTARG ;;
+ b) BATCHES=$OPTARG ;;
+ ?)
+ echo "Usage: %0 [-s <subscribers>] [-m <messages.] [-b <batches>]"
+ exit 1
+ ;;
+ esac
+done
+
+MY_DIR=$(dirname $(which $0))
+PYTHON_DIR=${MY_DIR}/../../../python
+
+trap stop_brokers EXIT
+
+start_broker() {
+ ${MY_DIR}/../qpidd --daemon --port 0 --no-module-dir --no-data-dir --auth no > qpidd.port
+}
+
+start_brokers() {
+ start_broker
+ PORT_A=`cat qpidd.port`
+ start_broker
+ PORT_B=`cat qpidd.port`
+ start_broker
+ PORT_C=`cat qpidd.port`
+}
+
+stop_brokers() {
+ for p in $PORT_A $PORT_B $PORT_C; do
+ ${MY_DIR}/../qpidd -q --port $p
+ done
+}
+
+subscribe() {
+ #which broker should we connect to?
+ if (( $1 % 2 )); then
+ MY_PORT=$PORT_C;
+ else
+ MY_PORT=$PORT_A;
+ fi
+
+ echo Subscriber $1 connecting on $MY_PORT
+ LOG="subscriber_$1.log"
+ ${MY_DIR}/topic_listener -p $MY_PORT > $LOG 2>&1 && rm -f $LOG
+}
+
+publish() {
+ ${MY_DIR}/topic_publisher --messages $MESSAGES --batches $BATCHES --subscribers $SUBSCRIBERS -p $PORT_A
+}
+
+setup_routes() {
+ BROKER_A="localhost:$PORT_A"
+ BROKER_B="localhost:$PORT_B"
+ BROKER_C="localhost:$PORT_C"
+ export PYTHONPATH=$PYTHON_DIR
+ if (($VERBOSE)); then
+ echo "Establishing routes for topic..."
+ fi
+ $PYTHON_DIR/commands/qpid-route route add $BROKER_B $BROKER_A amq.topic topic_control B B
+ $PYTHON_DIR/commands/qpid-route route add $BROKER_C $BROKER_B amq.topic topic_control C C
+ if (($VERBOSE)); then
+ echo "linked A->B->C"
+ fi
+ $PYTHON_DIR/commands/qpid-route route add $BROKER_B $BROKER_C amq.topic topic_control B B
+ $PYTHON_DIR/commands/qpid-route route add $BROKER_A $BROKER_B amq.topic topic_control A A
+ if (($VERBOSE)); then
+ echo "linked C->B->A"
+ echo "Establishing routes for response queue..."
+ fi
+
+ $PYTHON_DIR/commands/qpid-route route add $BROKER_B $BROKER_C amq.direct response B B
+ $PYTHON_DIR/commands/qpid-route route add $BROKER_A $BROKER_B amq.direct response A A
+ if (($VERBOSE)); then
+ echo "linked C->B->A"
+ for b in $BROKER_A $BROKER_B $BROKER_C; do
+ echo "Routes for $b"
+ $PYTHON_DIR/commands/qpid-route route list $b
+ done
+ fi
+}
+
+if test -d ${PYTHON_DIR} ; then
+ start_brokers
+ if (($VERBOSE)); then
+ echo "Running federated topic test against brokers on ports $PORT_A $PORT_B $PORT_C"
+ fi
+
+ for ((i=$SUBSCRIBERS ; i--; )); do
+ subscribe $i &
+ done
+
+ setup_routes
+
+ publish || exit 1
+fi
diff --git a/RC9/qpid/cpp/src/tests/federation.py b/RC9/qpid/cpp/src/tests/federation.py
new file mode 100755
index 0000000000..ad82964007
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/federation.py
@@ -0,0 +1,505 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import sys
+from qpid.testlib import TestBase010, testrunner
+from qpid.datatypes import Message
+from qpid.queue import Empty
+from time import sleep
+
+def add_module(args=sys.argv[1:]):
+ for a in args:
+ if a.startswith("federation"):
+ return False
+ return True
+
+def scan_args(name, default=None, args=sys.argv[1:]):
+ if (name in args):
+ pos = args.index(name)
+ return args[pos + 1]
+ elif default:
+ return default
+ else:
+ print "Please specify extra argument: %s" % name
+ sys.exit(2)
+
+def extract_args(name, args):
+ if (name in args):
+ pos = args.index(name)
+ del args[pos:pos+2]
+ else:
+ return None
+
+def remote_host():
+ return scan_args("--remote-host", "localhost")
+
+def remote_port():
+ return int(scan_args("--remote-port"))
+
+class FederationTests(TestBase010):
+
+ def test_bridge_create_and_close(self):
+ self.startQmf();
+ qmf = self.qmf
+
+ broker = qmf.getObjects(_class="broker")[0]
+ result = broker.connect(remote_host(), remote_port(), False, "PLAIN", "guest", "guest", "tcp")
+ self.assertEqual(result.status, 0)
+
+ link = qmf.getObjects(_class="link")[0]
+ result = link.bridge(False, "amq.direct", "amq.direct", "my-key", "", "", False, False, False)
+ self.assertEqual(result.status, 0)
+
+ bridge = qmf.getObjects(_class="bridge")[0]
+ result = bridge.close()
+ self.assertEqual(result.status, 0)
+
+ result = link.close()
+ self.assertEqual(result.status, 0)
+
+ sleep(3)
+ self.assertEqual(len(qmf.getObjects(_class="bridge")), 0)
+ self.assertEqual(len(qmf.getObjects(_class="link")), 0)
+
+ def test_pull_from_exchange(self):
+ session = self.session
+
+ self.startQmf()
+ qmf = self.qmf
+ broker = qmf.getObjects(_class="broker")[0]
+ result = broker.connect(remote_host(), remote_port(), False, "PLAIN", "guest", "guest", "tcp")
+ self.assertEqual(result.status, 0)
+
+ link = qmf.getObjects(_class="link")[0]
+ result = link.bridge(False, "amq.direct", "amq.fanout", "my-key", "", "", False, False, False)
+ self.assertEqual(result.status, 0)
+
+ bridge = qmf.getObjects(_class="bridge")[0]
+
+ #setup queue to receive messages from local broker
+ session.queue_declare(queue="fed1", exclusive=True, auto_delete=True)
+ session.exchange_bind(queue="fed1", exchange="amq.fanout")
+ self.subscribe(queue="fed1", destination="f1")
+ queue = session.incoming("f1")
+ sleep(6)
+
+ #send messages to remote broker and confirm it is routed to local broker
+ r_conn = self.connect(host=remote_host(), port=remote_port())
+ r_session = r_conn.session("test_pull_from_exchange")
+
+ for i in range(1, 11):
+ dp = r_session.delivery_properties(routing_key="my-key")
+ r_session.message_transfer(destination="amq.direct", message=Message(dp, "Message %d" % i))
+
+ for i in range(1, 11):
+ msg = queue.get(timeout=5)
+ self.assertEqual("Message %d" % i, msg.body)
+ try:
+ extra = queue.get(timeout=1)
+ self.fail("Got unexpected message in queue: " + extra.body)
+ except Empty: None
+
+ result = bridge.close()
+ self.assertEqual(result.status, 0)
+ result = link.close()
+ self.assertEqual(result.status, 0)
+
+ sleep(3)
+ self.assertEqual(len(qmf.getObjects(_class="bridge")), 0)
+ self.assertEqual(len(qmf.getObjects(_class="link")), 0)
+
+ def test_push_to_exchange(self):
+ session = self.session
+
+ self.startQmf()
+ qmf = self.qmf
+ broker = qmf.getObjects(_class="broker")[0]
+ result = broker.connect(remote_host(), remote_port(), False, "PLAIN", "guest", "guest", "tcp")
+ self.assertEqual(result.status, 0)
+
+ link = qmf.getObjects(_class="link")[0]
+ result = link.bridge(False, "amq.direct", "amq.fanout", "my-key", "", "", False, True, False)
+ self.assertEqual(result.status, 0)
+
+ bridge = qmf.getObjects(_class="bridge")[0]
+
+ #setup queue to receive messages from remote broker
+ r_conn = self.connect(host=remote_host(), port=remote_port())
+ r_session = r_conn.session("test_push_to_exchange")
+ r_session.queue_declare(queue="fed1", exclusive=True, auto_delete=True)
+ r_session.exchange_bind(queue="fed1", exchange="amq.fanout")
+ self.subscribe(session=r_session, queue="fed1", destination="f1")
+ queue = r_session.incoming("f1")
+ sleep(6)
+
+ #send messages to local broker and confirm it is routed to remote broker
+ for i in range(1, 11):
+ dp = session.delivery_properties(routing_key="my-key")
+ session.message_transfer(destination="amq.direct", message=Message(dp, "Message %d" % i))
+
+ for i in range(1, 11):
+ msg = queue.get(timeout=5)
+ self.assertEqual("Message %d" % i, msg.body)
+ try:
+ extra = queue.get(timeout=1)
+ self.fail("Got unexpected message in queue: " + extra.body)
+ except Empty: None
+
+ result = bridge.close()
+ self.assertEqual(result.status, 0)
+ result = link.close()
+ self.assertEqual(result.status, 0)
+
+ sleep(3)
+ self.assertEqual(len(qmf.getObjects(_class="bridge")), 0)
+ self.assertEqual(len(qmf.getObjects(_class="link")), 0)
+
+ def test_pull_from_queue(self):
+ session = self.session
+
+ #setup queue on remote broker and add some messages
+ r_conn = self.connect(host=remote_host(), port=remote_port())
+ r_session = r_conn.session("test_pull_from_queue")
+ r_session.queue_declare(queue="my-bridge-queue", auto_delete=True)
+ for i in range(1, 6):
+ dp = r_session.delivery_properties(routing_key="my-bridge-queue")
+ r_session.message_transfer(message=Message(dp, "Message %d" % i))
+
+ #setup queue to receive messages from local broker
+ session.queue_declare(queue="fed1", exclusive=True, auto_delete=True)
+ session.exchange_bind(queue="fed1", exchange="amq.fanout")
+ self.subscribe(queue="fed1", destination="f1")
+ queue = session.incoming("f1")
+
+ self.startQmf()
+ qmf = self.qmf
+ broker = qmf.getObjects(_class="broker")[0]
+ result = broker.connect(remote_host(), remote_port(), False, "PLAIN", "guest", "guest", "tcp")
+ self.assertEqual(result.status, 0)
+
+ link = qmf.getObjects(_class="link")[0]
+ result = link.bridge(False, "my-bridge-queue", "amq.fanout", "my-key", "", "", True, False, False)
+ self.assertEqual(result.status, 0)
+
+ bridge = qmf.getObjects(_class="bridge")[0]
+ sleep(3)
+
+ #add some more messages (i.e. after bridge was created)
+ for i in range(6, 11):
+ dp = r_session.delivery_properties(routing_key="my-bridge-queue")
+ r_session.message_transfer(message=Message(dp, "Message %d" % i))
+
+ for i in range(1, 11):
+ try:
+ msg = queue.get(timeout=5)
+ self.assertEqual("Message %d" % i, msg.body)
+ except Empty:
+ self.fail("Failed to find expected message containing 'Message %d'" % i)
+ try:
+ extra = queue.get(timeout=1)
+ self.fail("Got unexpected message in queue: " + extra.body)
+ except Empty: None
+
+ result = bridge.close()
+ self.assertEqual(result.status, 0)
+ result = link.close()
+ self.assertEqual(result.status, 0)
+
+ sleep(3)
+ self.assertEqual(len(qmf.getObjects(_class="bridge")), 0)
+ self.assertEqual(len(qmf.getObjects(_class="link")), 0)
+
+ def test_tracing_automatic(self):
+ remoteUrl = "%s:%d" % (remote_host(), remote_port())
+ self.startQmf()
+ l_broker = self.qmf_broker
+ r_broker = self.qmf.addBroker(remoteUrl)
+
+ l_brokerObj = self.qmf.getObjects(_class="broker", _broker=l_broker)[0]
+ r_brokerObj = self.qmf.getObjects(_class="broker", _broker=r_broker)[0]
+
+ l_res = l_brokerObj.connect(remote_host(), remote_port(), False, "PLAIN", "guest", "guest", "tcp")
+ r_res = r_brokerObj.connect(testrunner.host, testrunner.port, False, "PLAIN", "guest", "guest", "tcp")
+
+ self.assertEqual(l_res.status, 0)
+ self.assertEqual(r_res.status, 0)
+
+ l_link = self.qmf.getObjects(_class="link", _broker=l_broker)[0]
+ r_link = self.qmf.getObjects(_class="link", _broker=r_broker)[0]
+
+ l_res = l_link.bridge(False, "amq.direct", "amq.direct", "key", "", "", False, False, False)
+ r_res = r_link.bridge(False, "amq.direct", "amq.direct", "key", "", "", False, False, False)
+
+ self.assertEqual(l_res.status, 0)
+ self.assertEqual(r_res.status, 0)
+
+ count = 0
+ while l_link.state != "Operational" or r_link.state != "Operational":
+ count += 1
+ if count > 10:
+ self.fail("Fed links didn't become operational after 10 seconds")
+ sleep(1)
+ l_link = self.qmf.getObjects(_class="link", _broker=l_broker)[0]
+ r_link = self.qmf.getObjects(_class="link", _broker=r_broker)[0]
+ sleep(3)
+
+ #setup queue to receive messages from local broker
+ session = self.session
+ session.queue_declare(queue="fed1", exclusive=True, auto_delete=True)
+ session.exchange_bind(queue="fed1", exchange="amq.direct", binding_key="key")
+ self.subscribe(queue="fed1", destination="f1")
+ queue = session.incoming("f1")
+
+ #setup queue on remote broker and add some messages
+ r_conn = self.connect(host=remote_host(), port=remote_port())
+ r_session = r_conn.session("test_trace")
+ for i in range(1, 11):
+ dp = r_session.delivery_properties(routing_key="key")
+ r_session.message_transfer(destination="amq.direct", message=Message(dp, "Message %d" % i))
+
+ for i in range(1, 11):
+ try:
+ msg = queue.get(timeout=5)
+ self.assertEqual("Message %d" % i, msg.body)
+ except Empty:
+ self.fail("Failed to find expected message containing 'Message %d'" % i)
+ try:
+ extra = queue.get(timeout=1)
+ self.fail("Got unexpected message in queue: " + extra.body)
+ except Empty: None
+
+ def test_tracing(self):
+ session = self.session
+
+ self.startQmf()
+ qmf = self.qmf
+ broker = qmf.getObjects(_class="broker")[0]
+ result = broker.connect(remote_host(), remote_port(), False, "PLAIN", "guest", "guest", "tcp")
+ self.assertEqual(result.status, 0)
+
+ link = qmf.getObjects(_class="link")[0]
+ result = link.bridge(False, "amq.direct", "amq.fanout", "my-key", "my-bridge-id",
+ "exclude-me,also-exclude-me", False, False, False)
+ self.assertEqual(result.status, 0)
+ bridge = qmf.getObjects(_class="bridge")[0]
+
+ #setup queue to receive messages from local broker
+ session.queue_declare(queue="fed1", exclusive=True, auto_delete=True)
+ session.exchange_bind(queue="fed1", exchange="amq.fanout")
+ self.subscribe(queue="fed1", destination="f1")
+ queue = session.incoming("f1")
+ sleep(6)
+
+ #send messages to remote broker and confirm it is routed to local broker
+ r_conn = self.connect(host=remote_host(), port=remote_port())
+ r_session = r_conn.session("test_tracing")
+
+ trace = [None, "exclude-me", "a,exclude-me,b", "also-exclude-me,c", "dont-exclude-me"]
+ body = ["yes", "first-bad", "second-bad", "third-bad", "yes"]
+ for b, t in zip(body, trace):
+ headers = {}
+ if (t): headers["x-qpid.trace"]=t
+ dp = r_session.delivery_properties(routing_key="my-key")
+ mp = r_session.message_properties(application_headers=headers)
+ r_session.message_transfer(destination="amq.direct", message=Message(dp, mp, b))
+
+ for e in ["my-bridge-id", "dont-exclude-me,my-bridge-id"]:
+ msg = queue.get(timeout=5)
+ self.assertEqual("yes", msg.body)
+ self.assertEqual(e, self.getAppHeader(msg, "x-qpid.trace"))
+
+ try:
+ extra = queue.get(timeout=1)
+ self.fail("Got unexpected message in queue: " + extra.body)
+ except Empty: None
+
+ result = bridge.close()
+ self.assertEqual(result.status, 0)
+ result = link.close()
+ self.assertEqual(result.status, 0)
+
+ sleep(3)
+ self.assertEqual(len(qmf.getObjects(_class="bridge")), 0)
+ self.assertEqual(len(qmf.getObjects(_class="link")), 0)
+
+ def test_dynamic_fanout(self):
+ session = self.session
+ r_conn = self.connect(host=remote_host(), port=remote_port())
+ r_session = r_conn.session("test_dynamic_fanout")
+
+ session.exchange_declare(exchange="fed.fanout", type="fanout")
+ r_session.exchange_declare(exchange="fed.fanout", type="fanout")
+
+ self.startQmf()
+ qmf = self.qmf
+ broker = qmf.getObjects(_class="broker")[0]
+ result = broker.connect(remote_host(), remote_port(), False, "PLAIN", "guest", "guest", "tcp")
+ self.assertEqual(result.status, 0)
+
+ link = qmf.getObjects(_class="link")[0]
+ result = link.bridge(False, "fed.fanout", "fed.fanout", "", "", "", False, False, True)
+ self.assertEqual(result.status, 0)
+ bridge = qmf.getObjects(_class="bridge")[0]
+ sleep(5)
+
+ session.queue_declare(queue="fed1", exclusive=True, auto_delete=True)
+ session.exchange_bind(queue="fed1", exchange="fed.fanout")
+ self.subscribe(queue="fed1", destination="f1")
+ queue = session.incoming("f1")
+
+ for i in range(1, 11):
+ dp = r_session.delivery_properties()
+ r_session.message_transfer(destination="fed.fanout", message=Message(dp, "Message %d" % i))
+
+ for i in range(1, 11):
+ msg = queue.get(timeout=5)
+ self.assertEqual("Message %d" % i, msg.body)
+ try:
+ extra = queue.get(timeout=1)
+ self.fail("Got unexpected message in queue: " + extra.body)
+ except Empty: None
+
+ result = bridge.close()
+ self.assertEqual(result.status, 0)
+ result = link.close()
+ self.assertEqual(result.status, 0)
+
+ sleep(3)
+ self.assertEqual(len(qmf.getObjects(_class="bridge")), 0)
+ self.assertEqual(len(qmf.getObjects(_class="link")), 0)
+
+
+ def test_dynamic_direct(self):
+ session = self.session
+ r_conn = self.connect(host=remote_host(), port=remote_port())
+ r_session = r_conn.session("test_dynamic_direct")
+
+ session.exchange_declare(exchange="fed.direct", type="direct")
+ r_session.exchange_declare(exchange="fed.direct", type="direct")
+
+ self.startQmf()
+ qmf = self.qmf
+ broker = qmf.getObjects(_class="broker")[0]
+ result = broker.connect(remote_host(), remote_port(), False, "PLAIN", "guest", "guest", "tcp")
+ self.assertEqual(result.status, 0)
+
+ link = qmf.getObjects(_class="link")[0]
+ result = link.bridge(False, "fed.direct", "fed.direct", "", "", "", False, False, True)
+ self.assertEqual(result.status, 0)
+ bridge = qmf.getObjects(_class="bridge")[0]
+ sleep(5)
+
+ session.queue_declare(queue="fed1", exclusive=True, auto_delete=True)
+ session.exchange_bind(queue="fed1", exchange="fed.direct", binding_key="fd-key")
+ self.subscribe(queue="fed1", destination="f1")
+ queue = session.incoming("f1")
+
+ for i in range(1, 11):
+ dp = r_session.delivery_properties(routing_key="fd-key")
+ r_session.message_transfer(destination="fed.direct", message=Message(dp, "Message %d" % i))
+
+ for i in range(1, 11):
+ msg = queue.get(timeout=5)
+ self.assertEqual("Message %d" % i, msg.body)
+ try:
+ extra = queue.get(timeout=1)
+ self.fail("Got unexpected message in queue: " + extra.body)
+ except Empty: None
+
+ result = bridge.close()
+ self.assertEqual(result.status, 0)
+ result = link.close()
+ self.assertEqual(result.status, 0)
+
+ sleep(3)
+ self.assertEqual(len(qmf.getObjects(_class="bridge")), 0)
+ self.assertEqual(len(qmf.getObjects(_class="link")), 0)
+
+
+ def test_dynamic_topic(self):
+ session = self.session
+ r_conn = self.connect(host=remote_host(), port=remote_port())
+ r_session = r_conn.session("test_dynamic_topic")
+
+ session.exchange_declare(exchange="fed.topic", type="topic")
+ r_session.exchange_declare(exchange="fed.topic", type="topic")
+
+ self.startQmf()
+ qmf = self.qmf
+ broker = qmf.getObjects(_class="broker")[0]
+ result = broker.connect(remote_host(), remote_port(), False, "PLAIN", "guest", "guest", "tcp")
+ self.assertEqual(result.status, 0)
+
+ link = qmf.getObjects(_class="link")[0]
+ result = link.bridge(False, "fed.topic", "fed.topic", "", "", "", False, False, True)
+ self.assertEqual(result.status, 0)
+ bridge = qmf.getObjects(_class="bridge")[0]
+ sleep(5)
+
+ session.queue_declare(queue="fed1", exclusive=True, auto_delete=True)
+ session.exchange_bind(queue="fed1", exchange="fed.topic", binding_key="ft-key.#")
+ self.subscribe(queue="fed1", destination="f1")
+ queue = session.incoming("f1")
+
+ for i in range(1, 11):
+ dp = r_session.delivery_properties(routing_key="ft-key.one.two")
+ r_session.message_transfer(destination="fed.topic", message=Message(dp, "Message %d" % i))
+
+ for i in range(1, 11):
+ msg = queue.get(timeout=5)
+ self.assertEqual("Message %d" % i, msg.body)
+ try:
+ extra = queue.get(timeout=1)
+ self.fail("Got unexpected message in queue: " + extra.body)
+ except Empty: None
+
+ result = bridge.close()
+ self.assertEqual(result.status, 0)
+ result = link.close()
+ self.assertEqual(result.status, 0)
+
+ sleep(3)
+ self.assertEqual(len(qmf.getObjects(_class="bridge")), 0)
+ self.assertEqual(len(qmf.getObjects(_class="link")), 0)
+
+
+ def getProperty(self, msg, name):
+ for h in msg.headers:
+ if hasattr(h, name): return getattr(h, name)
+ return None
+
+ def getAppHeader(self, msg, name):
+ headers = self.getProperty(msg, "application_headers")
+ if headers:
+ return headers[name]
+ return None
+
+
+if __name__ == '__main__':
+ args = sys.argv[1:]
+ #need to remove the extra options from args as test runner doesn't recognise them
+ extract_args("--remote-port", args)
+ extract_args("--remote-host", args)
+
+ if add_module():
+ #add module(s) to run to testrunners args
+ args.append("federation")
+
+ if not testrunner.run(args): sys.exit(1)
diff --git a/RC9/qpid/cpp/src/tests/header_test.cpp b/RC9/qpid/cpp/src/tests/header_test.cpp
new file mode 100644
index 0000000000..ba9ffacc9b
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/header_test.cpp
@@ -0,0 +1,59 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <iostream>
+
+#include "TestOptions.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/Session.h"
+#include "qpid/client/SubscriptionManager.h"
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace std;
+
+int main(int argc, char** argv)
+{
+ TestOptions opts;
+ try {
+ opts.parse(argc, argv);
+ Connection connection;
+ connection.open(opts.con);
+ Session session = connection.newSession();
+ std::string q("header_interop_test_queue");
+ session.queueDeclare(arg::queue=q);
+ double pi = 3.14159265;
+ float e = 2.71828;
+ Message msg("", q);
+ msg.getMessageProperties().getApplicationHeaders().setDouble("pi", pi);
+ msg.getMessageProperties().getApplicationHeaders().setFloat("e", e);
+ session.messageTransfer(arg::content=msg);
+
+ session.close();
+ connection.close();
+
+ return 0;
+ } catch(const exception& e) {
+ cout << e.what() << endl;
+ }
+ return 1;
+}
diff --git a/RC9/qpid/cpp/src/tests/header_test.py b/RC9/qpid/cpp/src/tests/header_test.py
new file mode 100755
index 0000000000..d5a2c16c01
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/header_test.py
@@ -0,0 +1,86 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import qpid
+import sys
+import os
+from qpid.util import connect
+from qpid.connection import Connection
+from qpid.datatypes import Message, RangedSet, uuid4
+from qpid.queue import Empty
+from math import fabs
+
+def getApplicationHeaders(msg):
+ for h in msg.headers:
+ if hasattr(h, 'application_headers'): return getattr(h, 'application_headers')
+ return None
+
+# Set parameters for login
+
+host="127.0.0.1"
+port=5672
+user="guest"
+password="guest"
+
+if len(sys.argv) > 1 :
+ host=sys.argv[1]
+if len(sys.argv) > 2 :
+ port=int(sys.argv[2])
+
+# Create a connection.
+socket = connect(host, port)
+connection = Connection (sock=socket)
+connection.start()
+session = connection.session(str(uuid4()))
+
+q = "header_interop_test_queue"
+session.queue_declare(queue=q)
+
+session.message_subscribe(queue=q, destination="received")
+queue = session.incoming("received")
+queue.start()
+
+msg = queue.get(timeout=10)
+pi = 3.14159265
+e = 2.71828
+
+headers = getApplicationHeaders(msg)
+pi_ = headers["pi"]
+e_ = headers["e"]
+session.close(timeout=10)
+
+failed = False
+
+if pi != pi_:
+ print "got incorrect value for pi: ", pi_, " expected:", pi
+ failed = True
+
+if fabs(e - e_) > 0.0001:
+ print "got incorrect value for e: ", e_, " expected:", e
+ failed = True
+
+if failed:
+ sys.exit(1)
+else:
+ print "Correct header values received."
+ sys.exit(0)
+
+
+
diff --git a/RC9/qpid/cpp/src/tests/interop_runner.cpp b/RC9/qpid/cpp/src/tests/interop_runner.cpp
new file mode 100644
index 0000000000..8c6e0a6991
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/interop_runner.cpp
@@ -0,0 +1,251 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/Options.h"
+#include "qpid/ptr_map.h"
+#include "qpid/Exception.h"
+#include "qpid/client/Channel.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/ConnectionOptions.h"
+#include "qpid/client/Exchange.h"
+#include "qpid/client/MessageListener.h"
+#include "qpid/client/Queue.h"
+#include "qpid/sys/Thread.h"
+#include "qpid/sys/Time.h"
+#include <iostream>
+#include <memory>
+#include "BasicP2PTest.h"
+#include "BasicPubSubTest.h"
+#include "TestCase.h"
+#include <boost/ptr_container/ptr_map.hpp>
+
+/**
+ * Framework for interop tests.
+ *
+ * [see http://cwiki.apache.org/confluence/display/qpid/Interop+Testing+Specification for details].
+ */
+
+using namespace qpid::client;
+using namespace qpid::sys;
+using qpid::TestCase;
+using qpid::framing::FieldTable;
+using qpid::framing::ReplyTo;
+using namespace std;
+
+class DummyRun : public TestCase
+{
+public:
+ DummyRun() {}
+ void assign(const string&, FieldTable&, ConnectionOptions&) {}
+ void start() {}
+ void stop() {}
+ void report(qpid::client::Message&) {}
+};
+
+string parse_next_word(const string& input, const string& delims, string::size_type& position);
+
+/**
+ */
+class Listener : public MessageListener, private Runnable{
+ typedef boost::ptr_map<string, TestCase> TestMap;
+
+ Channel& channel;
+ ConnectionOptions& options;
+ TestMap tests;
+ const string name;
+ const string topic;
+ TestCase* test;
+ auto_ptr<Thread> runner;
+ ReplyTo reportTo;
+ string reportCorrelator;
+
+ void shutdown();
+ bool invite(const string& name);
+ void run();
+
+ void sendResponse(Message& response, ReplyTo replyTo);
+ void sendResponse(Message& response, Message& request);
+ void sendSimpleResponse(const string& type, Message& request);
+ void sendReport();
+public:
+ Listener(Channel& channel, ConnectionOptions& options);
+ void received(Message& msg);
+ void bindAndConsume();
+ void registerTest(string name, TestCase* test);
+};
+
+struct TestSettings : ConnectionOptions
+{
+ bool help;
+
+ TestSettings() : help(false)
+ {
+ addOptions()
+ ("help", qpid::optValue(help), "print this usage statement");
+ }
+};
+
+int main(int argc, char** argv) {
+ try {
+ TestSettings options;
+ options.parse(argc, argv);
+ if (options.help) {
+ cout << options;
+ } else {
+ Connection connection;
+ connection.open(options.host, options.port, "guest", "guest", options.virtualhost);
+
+ Channel channel;
+ connection.openChannel(channel);
+
+ Listener listener(channel, options);
+ listener.registerTest("TC1_DummyRun", new DummyRun());
+ listener.registerTest("TC2_BasicP2P", new qpid::BasicP2PTest());
+ listener.registerTest("TC3_BasicPubSub", new qpid::BasicPubSubTest());
+
+ listener.bindAndConsume();
+
+ channel.run();
+ connection.close();
+ }
+ } catch(const exception& error) {
+ cout << error.what() << endl << "Type " << argv[0] << " --help for help" << endl;
+ }
+}
+
+Listener::Listener(Channel& _channel, ConnectionOptions& _options) : channel(_channel), options(_options), name(options.clientid), topic("iop.control." + name)
+{}
+
+void Listener::registerTest(string name, TestCase* test)
+{
+ tests.insert(name, test);
+}
+
+void Listener::bindAndConsume()
+{
+ Queue control(name, true);
+ channel.declareQueue(control);
+ qpid::framing::FieldTable bindArgs;
+ //replace these separate binds with a wildcard once that is supported on java broker
+ channel.bind(Exchange::STANDARD_TOPIC_EXCHANGE, control, "iop.control", bindArgs);
+ channel.bind(Exchange::STANDARD_TOPIC_EXCHANGE, control, topic, bindArgs);
+
+ string tag;
+ channel.consume(control, tag, this);
+}
+
+void Listener::sendSimpleResponse(const string& type, Message& request)
+{
+ Message response;
+ response.getHeaders().setString("CONTROL_TYPE", type);
+ response.getHeaders().setString("CLIENT_NAME", name);
+ response.getHeaders().setString("CLIENT_PRIVATE_CONTROL_KEY", topic);
+ response.getMessageProperties().setCorrelationId(request.getMessageProperties().getCorrelationId());
+ sendResponse(response, request);
+}
+
+void Listener::sendResponse(Message& response, Message& request)
+{
+ sendResponse(response, request.getMessageProperties().getReplyTo());
+}
+
+void Listener::sendResponse(Message& response, ReplyTo replyTo)
+{
+ string exchange = replyTo.getExchange();
+ string routingKey = replyTo.getRoutingKey();
+ channel.publish(response, exchange, routingKey);
+}
+
+void Listener::received(Message& message)
+{
+ string type(message.getHeaders().getString("CONTROL_TYPE"));
+
+ if (type == "INVITE") {
+ string name(message.getHeaders().getString("TEST_NAME"));
+ if (name.empty() || invite(name)) {
+ sendSimpleResponse("ENLIST", message);
+ } else {
+ cout << "Can't take part in '" << name << "'" << endl;
+ }
+ } else if (type == "ASSIGN_ROLE") {
+ test->assign(message.getHeaders().getString("ROLE"), message.getHeaders(), options);
+ sendSimpleResponse("ACCEPT_ROLE", message);
+ } else if (type == "START") {
+ reportTo = message.getMessageProperties().getReplyTo();
+ reportCorrelator = message.getMessageProperties().getCorrelationId();
+ runner = auto_ptr<Thread>(new Thread(this));
+ } else if (type == "STATUS_REQUEST") {
+ reportTo = message.getMessageProperties().getReplyTo();
+ reportCorrelator = message.getMessageProperties().getCorrelationId();
+ test->stop();
+ sendReport();
+ } else if (type == "TERMINATE") {
+ if (test) test->stop();
+ shutdown();
+ } else {
+ cerr <<"ERROR!: Received unknown control message: " << type << endl;
+ shutdown();
+ }
+}
+
+void Listener::shutdown()
+{
+ channel.close();
+}
+
+bool Listener::invite(const string& name)
+{
+ TestMap::iterator i = tests.find(name);
+ test = (i != tests.end()) ? qpid::ptr_map_ptr(i) : 0;
+ return test;
+}
+
+void Listener::run()
+{
+ //NB: this method will be called in its own thread
+ //start test and when start returns...
+ test->start();
+ sendReport();
+}
+
+void Listener::sendReport()
+{
+ Message report;
+ report.getHeaders().setString("CONTROL_TYPE", "REPORT");
+ test->report(report);
+ report.getMessageProperties().setCorrelationId(reportCorrelator);
+ sendResponse(report, reportTo);
+}
+
+string parse_next_word(const string& input, const string& delims, string::size_type& position)
+{
+ string::size_type start = input.find_first_not_of(delims, position);
+ if (start == string::npos) {
+ return "";
+ } else {
+ string::size_type end = input.find_first_of(delims, start);
+ if (end == string::npos) {
+ end = input.length();
+ }
+ position = end;
+ return input.substr(start, end - start);
+ }
+}
diff --git a/RC9/qpid/cpp/src/tests/latencytest.cpp b/RC9/qpid/cpp/src/tests/latencytest.cpp
new file mode 100644
index 0000000000..6895964133
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/latencytest.cpp
@@ -0,0 +1,432 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+
+#include <algorithm>
+#include <limits>
+#include <iostream>
+#include <memory>
+#include <sstream>
+#include <vector>
+
+#include "TestOptions.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/sys/Time.h"
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace qpid::sys;
+using std::string;
+
+typedef std::vector<std::string> StringSet;
+
+struct Args : public qpid::TestOptions {
+ uint size;
+ uint count;
+ uint rate;
+ bool sync;
+ uint reportFrequency;
+ uint timeLimit;
+ uint queues;
+ uint prefetch;
+ uint ack;
+ bool cumulative;
+ bool csv;
+ bool durable;
+ string base;
+
+ Args() : size(256), count(1000), rate(0), reportFrequency(1000),
+ timeLimit(0), queues(1),
+ prefetch(100), ack(0),
+ durable(false), base("latency-test")
+ {
+ addOptions()
+
+ ("size", optValue(size, "N"), "message size")
+ ("queues", optValue(queues, "N"), "number of queues")
+ ("count", optValue(count, "N"), "number of messages to send")
+ ("rate", optValue(rate, "N"), "target message rate (causes count to be ignored)")
+ ("sync", optValue(sync), "send messages synchronously")
+ ("report-frequency", optValue(reportFrequency, "N"),
+ "number of milliseconds to wait between reports (ignored unless rate specified)")
+ ("time-limit", optValue(timeLimit, "N"),
+ "test duration, in seconds")
+ ("prefetch", optValue(prefetch, "N"), "prefetch count (0 implies no flow control, and no acking)")
+ ("ack", optValue(ack, "N"), "Ack frequency in messages (defaults to half the prefetch value)")
+ ("durable", optValue(durable, "yes|no"), "use durable messages")
+ ("csv", optValue(csv), "print stats in csv format (rate,min,max,avg)")
+ ("cumulative", optValue(cumulative), "cumulative stats in csv format")
+ ("queue-base-name", optValue(base, "<name>"), "base name for queues");
+ }
+};
+
+const std::string chars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
+
+Args opts;
+double c_min, c_avg, c_max;
+
+uint64_t current_time()
+{
+ Duration t(now());
+ return t;
+}
+
+struct Stats
+{
+ Mutex lock;
+ uint count;
+ double minLatency;
+ double maxLatency;
+ double totalLatency;
+
+ Stats();
+ void update(double l);
+ void print();
+ void reset();
+};
+
+class Client : public Runnable
+{
+protected:
+ Connection connection;
+ AsyncSession session;
+ Thread thread;
+ string queue;
+
+public:
+ Client(const string& q);
+ virtual ~Client() {}
+
+ void start();
+ void join();
+ void run();
+ virtual void test() = 0;
+};
+
+class Receiver : public Client, public MessageListener
+{
+ SubscriptionManager mgr;
+ uint count;
+ Stats& stats;
+
+public:
+ Receiver(const string& queue, Stats& stats);
+ void test();
+ void received(Message& msg);
+ Stats getStats();
+ uint getCount() { return count; }
+ void stop() { mgr.stop(); mgr.cancel(queue); }
+};
+
+
+class Sender : public Client
+{
+ string generateData(uint size);
+ void sendByRate();
+ void sendByCount();
+ Receiver& receiver;
+ const string data;
+public:
+ Sender(const string& queue, Receiver& receiver);
+ void test();
+};
+
+
+class Test
+{
+ const string queue;
+ Stats stats;
+ Receiver receiver;
+ Sender sender;
+ AbsTime begin;
+
+public:
+ Test(const string& q) : queue(q), receiver(queue, stats), sender(queue, receiver), begin(now()) {}
+ void start();
+ void join();
+ void report();
+};
+
+
+Client::Client(const string& q) : queue(q)
+{
+ opts.open(connection);
+ session = connection.newSession();
+}
+
+void Client::start()
+{
+ thread = Thread(this);
+}
+
+void Client::join()
+{
+ thread.join();
+}
+
+void Client::run()
+{
+ try{
+ test();
+ session.close();
+ connection.close();
+ } catch(const std::exception& e) {
+ std::cout << "Error in receiver: " << e.what() << std::endl;
+ }
+}
+
+Receiver::Receiver(const string& q, Stats& s) : Client(q), mgr(session), count(0), stats(s)
+{
+ session.queueDeclare(arg::queue=queue, arg::durable=opts.durable, arg::autoDelete=true);
+ uint msgCount = session.queueQuery(arg::queue=queue).get().getMessageCount();
+ if (msgCount) {
+ std::cout << "Warning: found " << msgCount << " msgs on " << queue << ". Purging..." << std::endl;
+ session.queuePurge(arg::queue=queue);
+ }
+ SubscriptionSettings settings;
+ if (opts.prefetch) {
+ settings.autoAck = (opts.ack ? opts.ack : (opts.prefetch / 2));
+ settings.flowControl = FlowControl::messageWindow(opts.prefetch);
+ } else {
+ settings.acceptMode = ACCEPT_MODE_NONE;
+ settings.flowControl = FlowControl::unlimited();
+ }
+ mgr.subscribe(*this, queue, settings);
+}
+
+void Receiver::test()
+{
+ mgr.run();
+ mgr.cancel(queue);
+}
+
+void Receiver::received(Message& msg)
+{
+ ++count;
+ uint64_t sentAt = msg.getDeliveryProperties().getTimestamp();
+ //uint64_t sentAt = msg.getHeaders().getTimestamp("sent-at");// TODO: add support for uint64_t as a field table type
+ uint64_t receivedAt = current_time();
+
+ //std::cerr << "Latency: " << (receivedAt - sentAt) << std::endl;
+ stats.update(((double) (receivedAt - sentAt)) / TIME_MSEC);
+
+ if (!opts.rate && count >= opts.count) {
+ mgr.stop();
+ }
+}
+
+void Stats::update(double latency)
+{
+ Mutex::ScopedLock l(lock);
+ count++;
+ minLatency = std::min(minLatency, latency);
+ maxLatency = std::max(maxLatency, latency);
+ totalLatency += latency;
+}
+
+Stats::Stats() : count(0), minLatency(std::numeric_limits<double>::max()), maxLatency(0), totalLatency(0) {}
+
+void Stats::print()
+{
+ static bool already_have_stats = false;
+ uint value;
+
+ if (opts.rate)
+ value = opts.rate;
+ else
+ value = opts.count;
+ Mutex::ScopedLock l(lock);
+ double aux_avg = (totalLatency / count);
+ if (!opts.cumulative) {
+ if (!opts.csv) {
+ std::cout << "Latency(ms): min=" << minLatency << ", max=" <<
+ maxLatency << ", avg=" << aux_avg;
+ } else {
+ std::cout << value << "," << minLatency << "," << maxLatency <<
+ "," << aux_avg;
+ }
+ } else {
+ if (already_have_stats) {
+ c_avg = (c_min + aux_avg) / 2;
+ if (c_min > minLatency) c_min = minLatency;
+ if (c_max < maxLatency) c_max = maxLatency;
+ } else {
+ c_avg = aux_avg;
+ c_min = minLatency;
+ c_max = maxLatency;
+ already_have_stats = true;
+ }
+ std::cout << value << "," << c_min << "," << c_max <<
+ "," << c_avg;
+ }
+
+}
+
+void Stats::reset()
+{
+ Mutex::ScopedLock l(lock);
+ count = 0;
+ totalLatency = maxLatency = 0;
+ minLatency = std::numeric_limits<double>::max();
+}
+
+Sender::Sender(const string& q, Receiver& receiver) : Client(q), receiver(receiver), data(generateData(opts.size)) {}
+
+void Sender::test()
+{
+ if (opts.rate) sendByRate();
+ else sendByCount();
+}
+
+void Sender::sendByCount()
+{
+ Message msg(data, queue);
+ if (opts.durable) {
+ msg.getDeliveryProperties().setDeliveryMode(framing::PERSISTENT);
+ }
+
+ for (uint i = 0; i < opts.count; i++) {
+ uint64_t sentAt(current_time());
+ msg.getDeliveryProperties().setTimestamp(sentAt);
+ async(session).messageTransfer(arg::content=msg, arg::acceptMode=1);
+ if (opts.sync) session.sync();
+ }
+ session.sync();
+}
+
+void Sender::sendByRate()
+{
+ Message msg(data, queue);
+ if (opts.durable) {
+ msg.getDeliveryProperties().setDeliveryMode(framing::PERSISTENT);
+ }
+
+ //calculate interval (in micro secs) between messages to achieve desired rate
+ uint64_t interval = (1000*1000)/opts.rate;
+ uint64_t timeLimit(opts.timeLimit * TIME_SEC);
+ uint64_t start(current_time());
+
+ while (true) {
+ uint64_t start_msg(current_time());
+ msg.getDeliveryProperties().setTimestamp(start_msg);
+ async(session).messageTransfer(arg::content=msg, arg::acceptMode=1);
+ if (opts.sync) session.sync();
+
+ uint64_t now = current_time();
+
+ if (timeLimit != 0 && (now - start) > timeLimit) {
+ session.sync();
+ receiver.stop();
+ break;
+ }
+
+ uint64_t timeTaken = (now - start_msg) / TIME_USEC;
+ if (timeTaken < interval) {
+ qpid::sys::usleep(interval - timeTaken);
+ } else if (timeTaken > interval &&
+ !opts.csv && !opts.cumulative) { // Don't be so verbose in this case, we're piping the results to another program
+ std::cout << "Could not achieve desired rate! (Took " << timeTaken
+ << " microsecs to send message, aiming for " << interval << " microsecs)" << std::endl;
+ }
+ }
+}
+
+string Sender::generateData(uint size)
+{
+ if (size < chars.length()) {
+ return chars.substr(0, size);
+ }
+ std::string data;
+ for (uint i = 0; i < (size / chars.length()); i++) {
+ data += chars;
+ }
+ data += chars.substr(0, size % chars.length());
+ return data;
+}
+
+
+void Test::start()
+{
+ receiver.start();
+ begin = AbsTime(now());
+ sender.start();
+}
+
+void Test::join()
+{
+ sender.join();
+ receiver.join();
+ AbsTime end = now();
+ Duration time(begin, end);
+ double msecs(time / TIME_MSEC);
+ if (!opts.csv) {
+ std::cout << "Sent " << receiver.getCount() << " msgs through " << queue
+ << " in " << msecs << "ms (" << (receiver.getCount() * 1000 / msecs) << " msgs/s) ";
+ }
+ stats.print();
+ std::cout << std::endl;
+}
+
+void Test::report()
+{
+ stats.print();
+ std::cout << std::endl;
+ stats.reset();
+}
+
+int main(int argc, char** argv)
+{
+ try {
+ opts.parse(argc, argv);
+ if (opts.cumulative)
+ opts.csv = true;
+ boost::ptr_vector<Test> tests(opts.queues);
+ for (uint i = 0; i < opts.queues; i++) {
+ std::ostringstream out;
+ out << opts.base << "-" << (i+1);
+ tests.push_back(new Test(out.str()));
+ }
+ for (boost::ptr_vector<Test>::iterator i = tests.begin(); i != tests.end(); i++) {
+ i->start();
+ }
+ if (opts.rate && !opts.timeLimit) {
+ while (true) {
+ qpid::sys::usleep(opts.reportFrequency * 1000);
+ //print latency report:
+ for (boost::ptr_vector<Test>::iterator i = tests.begin(); i != tests.end(); i++) {
+ i->report();
+ }
+ }
+ } else {
+ for (boost::ptr_vector<Test>::iterator i = tests.begin(); i != tests.end(); i++) {
+ i->join();
+ }
+ }
+
+ return 0;
+ } catch(const std::exception& e) {
+ std::cout << e.what() << std::endl;
+ }
+ return 1;
+}
diff --git a/RC9/qpid/cpp/src/tests/logging.cpp b/RC9/qpid/cpp/src/tests/logging.cpp
new file mode 100644
index 0000000000..051722e7c8
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/logging.cpp
@@ -0,0 +1,366 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test_tools.h"
+#include "qpid/log/Logger.h"
+#include "qpid/log/Options.h"
+#include "qpid/log/OstreamOutput.h"
+#include "qpid/memory.h"
+#include "qpid/Options.h"
+#if defined (_WIN32)
+#else
+# include "qpid/log/posix/SinkOptions.h"
+#endif
+
+#include <boost/test/floating_point_comparison.hpp>
+#include <boost/format.hpp>
+#include "unit_test.h"
+
+#include <exception>
+#include <fstream>
+#include <time.h>
+
+
+QPID_AUTO_TEST_SUITE(loggingTestSuite)
+
+using namespace std;
+using namespace boost;
+using namespace qpid::log;
+
+QPID_AUTO_TEST_CASE(testStatementInit) {
+ Statement s=QPID_LOG_STATEMENT_INIT(debug); int line=__LINE__;
+ BOOST_CHECK(!s.enabled);
+ BOOST_CHECK_EQUAL(string(__FILE__), s.file);
+ BOOST_CHECK_EQUAL(line, s.line);
+ BOOST_CHECK_EQUAL(debug, s.level);
+}
+
+
+QPID_AUTO_TEST_CASE(testSelector_enable) {
+ Selector s;
+ // Simple enable
+ s.enable(debug,"foo");
+ BOOST_CHECK(s.isEnabled(debug,"foo"));
+ BOOST_CHECK(!s.isEnabled(error,"foo"));
+ BOOST_CHECK(!s.isEnabled(error,"bar"));
+
+ // Substring match
+ BOOST_CHECK(s.isEnabled(debug, "bazfoobar"));
+ BOOST_CHECK(!s.isEnabled(debug, "bazbar"));
+
+ // Different levels for different substrings.
+ s.enable(info, "bar");
+ BOOST_CHECK(s.isEnabled(debug, "foobar"));
+ BOOST_CHECK(s.isEnabled(info, "foobar"));
+ BOOST_CHECK(!s.isEnabled(debug, "bar"));
+ BOOST_CHECK(!s.isEnabled(info, "foo"));
+
+ // Enable-strings
+ s.enable("notice:blob");
+ BOOST_CHECK(s.isEnabled(notice, "blob"));
+ s.enable("error+:oops");
+ BOOST_CHECK(s.isEnabled(error, "oops"));
+ BOOST_CHECK(s.isEnabled(critical, "oops"));
+}
+
+QPID_AUTO_TEST_CASE(testStatementEnabled) {
+ // Verify that the singleton enables and disables static
+ // log statements.
+ Logger& l = Logger::instance();
+ ScopedSuppressLogging ls(l);
+ l.select(Selector(debug));
+ static Statement s=QPID_LOG_STATEMENT_INIT(debug);
+ BOOST_CHECK(!s.enabled);
+ static Statement::Initializer init(s);
+ BOOST_CHECK(s.enabled);
+
+ static Statement s2=QPID_LOG_STATEMENT_INIT(warning);
+ static Statement::Initializer init2(s2);
+ BOOST_CHECK(!s2.enabled);
+
+ l.select(Selector(warning));
+ BOOST_CHECK(!s.enabled);
+ BOOST_CHECK(s2.enabled);
+}
+
+struct TestOutput : public Logger::Output {
+ vector<string> msg;
+ vector<Statement> stmt;
+
+ TestOutput(Logger& l) {
+ l.output(std::auto_ptr<Logger::Output>(this));
+ }
+
+ void log(const Statement& s, const string& m) {
+ msg.push_back(m);
+ stmt.push_back(s);
+ }
+ string last() { return msg.back(); }
+};
+
+using boost::assign::list_of;
+
+QPID_AUTO_TEST_CASE(testLoggerOutput) {
+ Logger l;
+ l.clear();
+ l.select(Selector(debug));
+ Statement s=QPID_LOG_STATEMENT_INIT(debug);
+
+ TestOutput* out=new TestOutput(l);
+
+ // Verify message is output.
+ l.log(s, "foo");
+ vector<string> expect=list_of("foo\n");
+ BOOST_CHECK_EQUAL(expect, out->msg);
+
+ // Verify multiple outputs
+ TestOutput* out2=new TestOutput(l);
+ l.log(Statement(), "baz");
+ expect.push_back("baz\n");
+ BOOST_CHECK_EQUAL(expect, out->msg);
+ expect.erase(expect.begin());
+ BOOST_CHECK_EQUAL(expect, out2->msg);
+}
+
+QPID_AUTO_TEST_CASE(testMacro) {
+ Logger& l=Logger::instance();
+ ScopedSuppressLogging ls(l);
+ l.select(Selector(info));
+ TestOutput* out=new TestOutput(l);
+ QPID_LOG(info, "foo");
+ vector<string> expect=list_of("foo\n");
+ BOOST_CHECK_EQUAL(expect, out->msg);
+ BOOST_CHECK_EQUAL(__FILE__, out->stmt.front().file);
+
+ // Not enabled:
+ QPID_LOG(debug, "bar");
+ BOOST_CHECK_EQUAL(expect, out->msg);
+
+ QPID_LOG(info, 42 << " bingo");
+ expect.push_back("42 bingo\n");
+ BOOST_CHECK_EQUAL(expect, out->msg);
+}
+
+QPID_AUTO_TEST_CASE(testLoggerFormat) {
+ Logger& l = Logger::instance();
+ ScopedSuppressLogging ls(l);
+ l.select(Selector(critical));
+ TestOutput* out=new TestOutput(l);
+
+ l.format(Logger::FILE);
+ QPID_LOG(critical, "foo");
+ BOOST_CHECK_EQUAL(out->last(), string(__FILE__)+": foo\n");
+
+ l.format(Logger::FILE|Logger::LINE);
+ QPID_LOG(critical, "foo");
+ BOOST_CHECK_REGEX(string(__FILE__)+":\\d+: foo\n", out->last());
+
+ l.format(Logger::FUNCTION);
+ QPID_LOG(critical, "foo");
+ BOOST_CHECK_REGEX("void .*testLoggerFormat.*\\(\\): foo\n", out->last());
+
+ l.format(Logger::LEVEL);
+ QPID_LOG(critical, "foo");
+ BOOST_CHECK_EQUAL("critical foo\n", out->last());
+}
+
+QPID_AUTO_TEST_CASE(testOstreamOutput) {
+ Logger& l=Logger::instance();
+ ScopedSuppressLogging ls(l);
+ l.select(Selector(error));
+ ostringstream os;
+ l.output(qpid::make_auto_ptr<Logger::Output>(new OstreamOutput(os)));
+ QPID_LOG(error, "foo");
+ QPID_LOG(error, "bar");
+ QPID_LOG(error, "baz");
+ BOOST_CHECK_EQUAL("foo\nbar\nbaz\n", os.str());
+}
+
+#if 0 // This test requires manual intervention. Normally disabled.
+QPID_AUTO_TEST_CASE(testSyslogOutput) {
+ Logger& l=Logger::instance();
+ Logger::StateSaver ls(l);
+ l.clear();
+ l.select(Selector(info));
+ l.syslog("qpid_test");
+ QPID_LOG(info, "Testing QPID");
+ BOOST_ERROR("Manually verify that /var/log/messages contains a recent line 'Testing QPID'");
+}
+#endif // 0
+
+int count() {
+ static int n = 0;
+ return n++;
+}
+
+int loggedCount() {
+ static int n = 0;
+ QPID_LOG(debug, "counting: " << n);
+ return n++;
+}
+
+
+using namespace qpid::sys;
+
+// Measure CPU time.
+clock_t timeLoop(int times, int (*fp)()) {
+ clock_t start=clock();
+ while (times-- > 0)
+ (*fp)();
+ return clock() - start;
+}
+
+// Overhead test disabled because it consumes a ton of CPU and takes
+// forever under valgrind. Not friendly for regular test runs.
+//
+#if 0
+QPID_AUTO_TEST_CASE(testOverhead) {
+ // Ensure that the ratio of CPU time for an incrementing loop
+ // with and without disabled log statements is in acceptable limits.
+ //
+ int times=100000000;
+ clock_t noLog=timeLoop(times, count);
+ clock_t withLog=timeLoop(times, loggedCount);
+ double ratio=double(withLog)/double(noLog);
+
+ // NB: in initial tests the ratio was consistently below 1.5,
+ // 2.5 is reasonable and should avoid spurios failures
+ // due to machine load.
+ //
+ BOOST_CHECK_SMALL(ratio, 2.5);
+}
+#endif // 0
+
+Statement statement(
+ Level level, const char* file="", int line=0, const char* fn=0)
+{
+ Statement s={0, file, line, fn, level};
+ return s;
+}
+
+
+#define ARGC(argv) (sizeof(argv)/sizeof(char*))
+
+QPID_AUTO_TEST_CASE(testOptionsParse) {
+ const char* argv[]={
+ 0,
+ "--log-enable", "error+:foo",
+ "--log-enable", "debug:bar",
+ "--log-enable", "info",
+ "--log-to-stderr", "no",
+ "--log-to-file", "logout",
+ "--log-level", "yes",
+ "--log-source", "1",
+ "--log-thread", "true",
+ "--log-function", "YES"
+ };
+ qpid::log::Options opts("");
+ qpid::log::posix::SinkOptions sinks("test");
+ opts.parse(ARGC(argv), const_cast<char**>(argv));
+ sinks = *opts.sinkOptions;
+ vector<string> expect=list_of("error+:foo")("debug:bar")("info");
+ BOOST_CHECK_EQUAL(expect, opts.selectors);
+ BOOST_CHECK(!sinks.logToStderr);
+ BOOST_CHECK(!sinks.logToStdout);
+ BOOST_CHECK(sinks.logFile == "logout");
+ BOOST_CHECK(opts.level);
+ BOOST_CHECK(opts.source);
+ BOOST_CHECK(opts.function);
+ BOOST_CHECK(opts.thread);
+}
+
+QPID_AUTO_TEST_CASE(testOptionsDefault) {
+ Options opts("");
+ qpid::log::posix::SinkOptions sinks("test");
+ sinks = *opts.sinkOptions;
+ BOOST_CHECK(sinks.logToStderr);
+ BOOST_CHECK(!sinks.logToStdout);
+ BOOST_CHECK(sinks.logFile.length() == 0);
+ vector<string> expect=list_of("notice+");
+ BOOST_CHECK_EQUAL(expect, opts.selectors);
+ BOOST_CHECK(opts.time && opts.level);
+ BOOST_CHECK(!(opts.source || opts.function || opts.thread));
+}
+
+QPID_AUTO_TEST_CASE(testSelectorFromOptions) {
+ const char* argv[]={
+ 0,
+ "--log-enable", "error+:foo",
+ "--log-enable", "debug:bar",
+ "--log-enable", "info"
+ };
+ qpid::log::Options opts("");
+ opts.parse(ARGC(argv), const_cast<char**>(argv));
+ vector<string> expect=list_of("error+:foo")("debug:bar")("info");
+ BOOST_CHECK_EQUAL(expect, opts.selectors);
+ Selector s(opts);
+ BOOST_CHECK(!s.isEnabled(warning, "x"));
+ BOOST_CHECK(!s.isEnabled(debug, "x"));
+ BOOST_CHECK(s.isEnabled(debug, "bar"));
+ BOOST_CHECK(s.isEnabled(error, "foo"));
+ BOOST_CHECK(s.isEnabled(critical, "foo"));
+}
+
+QPID_AUTO_TEST_CASE(testLoggerStateure) {
+ Logger& l=Logger::instance();
+ ScopedSuppressLogging ls(l);
+ Options opts("test");
+ const char* argv[]={
+ 0,
+ "--log-time", "no",
+ "--log-source", "yes",
+ "--log-to-stderr", "no",
+ "--log-to-file", "logging.tmp",
+ "--log-enable", "critical"
+ };
+ opts.parse(ARGC(argv), const_cast<char**>(argv));
+ l.configure(opts);
+ QPID_LOG(critical, "foo"); int srcline=__LINE__;
+ ifstream log("logging.tmp");
+ string line;
+ getline(log, line);
+ string expect=(format("critical %s:%d: foo")%__FILE__%srcline).str();
+ BOOST_CHECK_EQUAL(expect, line);
+ log.close();
+ unlink("logging.tmp");
+}
+
+QPID_AUTO_TEST_CASE(testQuoteNonPrintable) {
+ Logger& l=Logger::instance();
+ ScopedSuppressLogging ls(l);
+ Options opts("test");
+ opts.time=false;
+ qpid::log::posix::SinkOptions *sinks =
+ dynamic_cast<qpid::log::posix::SinkOptions *>(opts.sinkOptions.get());
+ sinks->logToStderr = false;
+ sinks->logFile = "logging.tmp";
+ l.configure(opts);
+
+ char s[] = "null\0tab\tspace newline\nret\r\x80\x99\xff";
+ string str(s, sizeof(s));
+ QPID_LOG(critical, str);
+ ifstream log("logging.tmp");
+ string line;
+ getline(log, line, '\0');
+ string expect="critical null\\x00tab\tspace newline\nret\r\\x80\\x99\\xFF\\x00\n";
+ BOOST_CHECK_EQUAL(expect, line);
+ log.close();
+ unlink("logging.tmp");
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/multiq_perftest b/RC9/qpid/cpp/src/tests/multiq_perftest
new file mode 100755
index 0000000000..10f9edd2a6
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/multiq_perftest
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+exec `dirname $0`/run_perftest 10000 --mode shared --qt 16
diff --git a/RC9/qpid/cpp/src/tests/perfdist b/RC9/qpid/cpp/src/tests/perfdist
new file mode 100755
index 0000000000..59548b23f7
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/perfdist
@@ -0,0 +1,87 @@
+#!/bin/bash
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+
+#
+# Distributed perftest.
+# Runs perftest clients on multiple hosts using ssh.
+#
+
+set -e
+usage() {
+cat <<EOF
+usage: $0 <perftest-args> -- <client-hosts ...> [ --- <broker hosts...> ]
+Client & broker hosts can also be set in env vars CLIENTS and BROKERS.
+
+Run perftest clients on the client hosts against brokers on the broker
+hosts Clients are assigned to client hosts round robin: publishers
+first, then subscribers. If there are multiple brokers (for cluster
+tests) clients connect to them round robin.
+
+Broker hosts can be listed with -b in perftest-args or after ---
+at the end of the arguments.
+
+Error: $*
+EOF
+exit 1
+}
+
+TESTDIR=${TESTDIR:-$PWD} # Absolute path to test exes on all hosts.
+
+collect() { eval $COLLECT=\""\$$COLLECT $*"\"; }
+NPUBS=1
+NSUBS=1
+COLLECT=ARGS
+while test $# -gt 0; do
+ case $1 in
+ --publish|--subscribe|--setup|--control) usage "Don't pass perftest action flags: $1" ;;
+ --npubs) collect $1 $2; NPUBS=$2; shift 2 ;;
+ --nsubs) collect $1 $2; NSUBS=$2; shift 2 ;;
+ -s|--summary) collect $1; QUIET=yes; shift 1 ;;
+ -b|--broker) BROKERS="$BROKERS $2"; shift 2;;
+ --) COLLECT=CLIENTARG; shift ;;
+ ---) COLLECT=BROKERARG; shift;;
+ *) collect $1; shift ;;
+ esac
+done
+
+CLIENTS=${CLIENTARG:-$CLIENTS}
+if [ -z "$CLIENTS" ]; then usage "No client hosts listed after --"; fi
+BROKERS=${BROKERARG:-$BROKERS}
+if [ -z "$BROKERS" ]; then usage "No brokers specified"; fi
+
+PERFTEST="$TESTDIR/perftest $ARGS"
+
+CLIENTS=($CLIENTS)
+BROKERS=($BROKERS)
+start() {
+ CLIENT=${CLIENTS[i % ${#CLIENTS[*]}]}
+ BROKER=${BROKERS[i % ${#BROKERS[*]}]}
+ ARGS="$* --broker $BROKER"
+ cmd="ssh -n $CLIENT $PERFTEST $ARGS"
+ test -z "$QUIET" && echo "Client $i: $cmd"
+ $cmd &
+}
+
+$PERFTEST --setup -b ${BROKERS[0]}
+for (( i=0 ; i < $NPUBS ; ++i)); do start --publish; done
+for (( ; i < $NPUBS+$NSUBS ; ++i)); do start --subscribe; done
+$PERFTEST --control -b ${BROKERS[0]}
diff --git a/RC9/qpid/cpp/src/tests/perftest.cpp b/RC9/qpid/cpp/src/tests/perftest.cpp
new file mode 100644
index 0000000000..be9ffd846e
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/perftest.cpp
@@ -0,0 +1,701 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "TestOptions.h"
+
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Completion.h"
+#include "qpid/client/Message.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/sys/Time.h"
+
+#include <boost/lexical_cast.hpp>
+#include <boost/bind.hpp>
+#include <boost/function.hpp>
+#include <boost/ptr_container/ptr_vector.hpp>
+
+#include <iostream>
+#include <sstream>
+#include <numeric>
+#include <algorithm>
+#include <unistd.h>
+#include <math.h>
+
+
+using namespace std;
+using namespace qpid;
+using namespace client;
+using namespace sys;
+using boost::lexical_cast;
+using boost::bind;
+
+enum Mode { SHARED, FANOUT, TOPIC };
+const char* modeNames[] = { "shared", "fanout", "topic" };
+
+// istream/ostream ops so Options can read/display Mode.
+istream& operator>>(istream& in, Mode& mode) {
+ string s;
+ in >> s;
+ int i = find(modeNames, modeNames+3, s) - modeNames;
+ if (i >= 3) throw Exception("Invalid mode: "+s);
+ mode = Mode(i);
+ return in;
+}
+
+ostream& operator<<(ostream& out, Mode mode) {
+ return out << modeNames[mode];
+}
+
+
+struct Opts : public TestOptions {
+
+ // Actions
+ bool setup, control, publish, subscribe;
+
+ // Queue policy
+ uint32_t queueMaxCount;
+ uint64_t queueMaxSize;
+ bool queueDurable;
+
+ // Publisher
+ size_t pubs;
+ size_t count ;
+ size_t size;
+ bool confirm;
+ bool durable;
+ bool uniqueData;
+ bool syncPub;
+
+ // Subscriber
+ size_t subs;
+ size_t ack;
+
+ // General
+ size_t qt;
+ size_t iterations;
+ Mode mode;
+ bool summary;
+ uint32_t intervalSub;
+ uint32_t intervalPub;
+ size_t tx;
+ size_t txPub;
+ size_t txSub;
+ bool commitAsync;
+
+ static const std::string helpText;
+
+ Opts() :
+ TestOptions(helpText),
+ setup(false), control(false), publish(false), subscribe(false),
+ pubs(1), count(500000), size(1024), confirm(true), durable(false), uniqueData(false), syncPub(false),
+ subs(1), ack(0),
+ qt(1), iterations(1), mode(SHARED), summary(false),
+ intervalSub(0), intervalPub(0), tx(0), txPub(0), txSub(0), commitAsync(false)
+ {
+ addOptions()
+ ("setup", optValue(setup), "Create shared queues.")
+ ("control", optValue(control), "Run test, print report.")
+ ("publish", optValue(publish), "Publish messages.")
+ ("subscribe", optValue(subscribe), "Subscribe for messages.")
+
+ ("mode", optValue(mode, "shared|fanout|topic"), "Test mode."
+ "\nshared: --qt queues, --npubs publishers and --nsubs subscribers per queue.\n"
+ "\nfanout: --npubs publishers, --nsubs subscribers, fanout exchange."
+ "\ntopic: --qt topics, --npubs publishers and --nsubs subscribers per topic.\n")
+
+ ("npubs", optValue(pubs, "N"), "Create N publishers.")
+ ("count", optValue(count, "N"), "Each publisher sends N messages.")
+ ("size", optValue(size, "BYTES"), "Size of messages in bytes.")
+ ("pub-confirm", optValue(confirm, "yes|no"), "Publisher use confirm-mode.")
+ ("durable", optValue(durable, "yes|no"), "Publish messages as durable.")
+ ("unique-data", optValue(uniqueData, "yes|no"), "Make data for each message unique.")
+ ("sync-publish", optValue(syncPub, "yes|no"), "Wait for confirmation of each message before sending the next one.")
+
+ ("nsubs", optValue(subs, "N"), "Create N subscribers.")
+ ("sub-ack", optValue(ack, "N"), "N>0: Subscriber acks batches of N.\n"
+ "N==0: Subscriber uses unconfirmed mode")
+
+ ("qt", optValue(qt, "N"), "Create N queues or topics.")
+ ("iterations", optValue(iterations, "N"), "Desired number of iterations of the test.")
+ ("summary,s", optValue(summary), "Summary output: pubs/sec subs/sec transfers/sec Mbytes/sec")
+
+ ("queue-max-count", optValue(queueMaxCount, "N"), "queue policy: count to trigger 'flow to disk'")
+ ("queue-max-size", optValue(queueMaxSize, "N"), "queue policy: accumulated size to trigger 'flow to disk'")
+ ("queue-durable", optValue(queueDurable, "N"), "Make queue durable (implied if durable set)")
+
+ ("interval_sub", optValue(intervalSub, "ms"), ">=0 delay between msg consume")
+ ("interval_pub", optValue(intervalPub, "ms"), ">=0 delay between msg publish")
+
+ ("tx", optValue(tx, "N"), "if non-zero, the transaction batch size for publishing and consuming")
+ ("pub-tx", optValue(txPub, "N"), "if non-zero, the transaction batch size for publishing")
+ ("async-commit", optValue(commitAsync, "yes|no"), "Don't wait for completion of commit")
+ ("sub-tx", optValue(txSub, "N"), "if non-zero, the transaction batch size for consuming");
+ }
+
+ // Computed values
+ size_t totalPubs;
+ size_t totalSubs;
+ size_t transfers;
+ size_t subQuota;
+
+ void parse(int argc, char** argv) {
+ TestOptions::parse(argc, argv);
+ switch (mode) {
+ case SHARED:
+ if (count % subs) {
+ count += subs - (count % subs);
+ cout << "WARNING: Adjusted --count to " << count
+ << " the nearest multiple of --nsubs" << endl;
+ }
+ totalPubs = pubs*qt;
+ totalSubs = subs*qt;
+ subQuota = (pubs*count)/subs;
+ break;
+ case FANOUT:
+ if (qt != 1) cerr << "WARNING: Fanout mode, ignoring --qt="
+ << qt << endl;
+ qt=1;
+ totalPubs = pubs;
+ totalSubs = subs;
+ subQuota = totalPubs*count;
+ break;
+ case TOPIC:
+ totalPubs = pubs*qt;
+ totalSubs = subs*qt;
+ subQuota = pubs*count;
+ break;
+ }
+ transfers=(totalPubs*count) + (totalSubs*subQuota);
+ if (tx) {
+ if (txPub) {
+ cerr << "WARNING: Using overriden tx value for publishers: " << txPub << std::endl;
+ } else {
+ txPub = tx;
+ }
+ if (txSub) {
+ cerr << "WARNING: Using overriden tx value for subscribers: " << txSub << std::endl;
+ } else {
+ txSub = tx;
+ }
+ }
+ }
+};
+
+const std::string Opts::helpText=
+"There are two ways to use perftest: single process or multi-process.\n\n"
+"If none of the --setup, --publish, --subscribe or --control options\n"
+"are given perftest will run a single-process test.\n"
+"For a multi-process test first run:\n"
+" perftest --setup <other options>\n"
+"and wait for it to complete. The remaining process should run concurrently::\n"
+"Run --npubs times: perftest --publish <other options>\n"
+"Run --nsubs times: perftest --subscribe <other options>\n"
+"Run once: perftest --control <other options>\n"
+"Note the <other options> must be identical for all processes.\n";
+
+Opts opts;
+
+struct Client : public Runnable {
+ Connection connection;
+ AsyncSession session;
+ Thread thread;
+
+ Client() {
+ opts.open(connection);
+ session = connection.newSession();
+ }
+
+ ~Client() {
+ try {
+ session.close();
+ connection.close();
+ } catch (const std::exception& e) {
+ std::cerr << "Error in shutdown: " << e.what() << std::endl;
+ }
+ }
+};
+
+struct Setup : public Client {
+
+ void queueInit(string name, bool durable=false, const framing::FieldTable& settings=framing::FieldTable()) {
+ session.queueDeclare(arg::queue=name, arg::durable=durable, arg::arguments=settings);
+ session.queuePurge(arg::queue=name);
+ session.sync();
+ }
+
+ void run() {
+ queueInit("pub_start");
+ queueInit("pub_done");
+ queueInit("sub_ready");
+ queueInit("sub_done");
+ if (opts.mode==SHARED) {
+ framing::FieldTable settings;//queue policy settings
+ settings.setInt("qpid.max_count", opts.queueMaxCount);
+ settings.setInt("qpid.max_size", opts.queueMaxSize);
+ for (size_t i = 0; i < opts.qt; ++i) {
+ ostringstream qname;
+ qname << "perftest" << i;
+ queueInit(qname.str(), opts.durable || opts.queueDurable, settings);
+ }
+ }
+ }
+};
+
+void expect(string actual, string expect) {
+ if (expect != actual)
+ throw Exception("Expecting "+expect+" but received "+actual);
+
+}
+
+double secs(Duration d) { return double(d)/TIME_SEC; }
+double secs(AbsTime start, AbsTime finish) {
+ return secs(Duration(start,finish));
+}
+
+
+// Collect rates & print stats.
+class Stats {
+ vector<double> values;
+ double sum;
+
+ public:
+ Stats() : sum(0) {}
+
+ // Functor to collect rates.
+ void operator()(const string& data) {
+ try {
+ double d=lexical_cast<double>(data);
+ values.push_back(d);
+ sum += d;
+ } catch (const std::exception&) {
+ throw Exception("Bad report: "+data);
+ }
+ }
+
+ double mean() const {
+ return sum/values.size();
+ }
+
+ double stdev() const {
+ if (values.size() <= 1) return 0;
+ double avg = mean();
+ double ssq = 0;
+ for (vector<double>::const_iterator i = values.begin();
+ i != values.end(); ++i) {
+ double x=*i;
+ x -= avg;
+ ssq += x*x;
+ }
+ return sqrt(ssq/(values.size()-1));
+ }
+
+ ostream& print(ostream& out) {
+ ostream_iterator<double> o(out, "\n");
+ copy(values.begin(), values.end(), o);
+ out << "Average: " << mean();
+ if (values.size() > 1)
+ out << " (std.dev. " << stdev() << ")";
+ return out << endl;
+ }
+};
+
+
+// Manage control queues, collect and print reports.
+struct Controller : public Client {
+
+ SubscriptionManager subs;
+
+ Controller() : subs(session) {}
+
+ /** Process messages from queue by applying a functor. */
+ void process(size_t n, string queue,
+ boost::function<void (const string&)> msgFn)
+ {
+ if (!opts.summary)
+ cout << "Processing " << n << " messages from "
+ << queue << " " << flush;
+ LocalQueue lq;
+ subs.setFlowControl(n, SubscriptionManager::UNLIMITED, false);
+ subs.subscribe(lq, queue);
+ for (size_t i = 0; i < n; ++i) {
+ if (!opts.summary) cout << "." << flush;
+ msgFn(lq.pop().getData());
+ }
+ if (!opts.summary) cout << " done." << endl;
+ }
+
+ void process(size_t n, LocalQueue lq, string queue,
+ boost::function<void (const string&)> msgFn)
+ {
+ session.messageFlow(queue, 0, n);
+ if (!opts.summary)
+ cout << "Processing " << n << " messages from "
+ << queue << " " << flush;
+ for (size_t i = 0; i < n; ++i) {
+ if (!opts.summary) cout << "." << flush;
+ msgFn(lq.pop().getData());
+ }
+ if (!opts.summary) cout << " done." << endl;
+ }
+
+ void send(size_t n, string queue, string data) {
+ if (!opts.summary)
+ cout << "Sending " << data << " " << n << " times to " << queue
+ << endl;
+ Message msg(data, queue);
+ for (size_t i = 0; i < n; ++i)
+ session.messageTransfer(arg::content=msg, arg::acceptMode=1);
+ }
+
+ void run() { // Controller
+ try {
+ // Wait for subscribers to be ready.
+ process(opts.totalSubs, "sub_ready", bind(expect, _1, "ready"));
+
+ LocalQueue pubDone;
+ LocalQueue subDone;
+ subs.setFlowControl(0, SubscriptionManager::UNLIMITED, false);
+ subs.subscribe(pubDone, "pub_done");
+ subs.subscribe(subDone, "sub_done");
+
+ double txrateTotal(0);
+ double mbytesTotal(0);
+ double pubRateTotal(0);
+ double subRateTotal(0);
+
+ for (size_t j = 0; j < opts.iterations; ++j) {
+ AbsTime start=now();
+ send(opts.totalPubs, "pub_start", "start"); // Start publishers
+
+ Stats pubRates;
+ Stats subRates;
+
+ process(opts.totalPubs, pubDone, "pub_done", boost::ref(pubRates));
+ process(opts.totalSubs, subDone, "sub_done", boost::ref(subRates));
+
+ AbsTime end=now();
+
+ double time=secs(start, end);
+ double txrate=opts.transfers/time;
+ double mbytes=(txrate*opts.size)/(1024*1024);
+
+ if (!opts.summary) {
+ cout << endl << "Total " << opts.transfers << " transfers of "
+ << opts.size << " bytes in "
+ << time << " seconds." << endl;
+ cout << endl << "Publish transfers/sec: " << endl;
+ pubRates.print(cout);
+ cout << endl << "Subscribe transfers/sec: " << endl;
+ subRates.print(cout);
+ cout << endl
+ << "Total transfers/sec: " << txrate << endl
+ << "Total Mbytes/sec: " << mbytes << endl;
+ }
+ else {
+ cout << pubRates.mean() << "\t"
+ << subRates.mean() << "\t"
+ << txrate << "\t"
+ << mbytes << endl;
+ }
+
+ txrateTotal += txrate;
+ mbytesTotal += mbytes;
+ pubRateTotal += pubRates.mean();
+ subRateTotal += subRates.mean();
+ }
+ if (opts.iterations > 1) {
+ cout << "Averages: "<< endl
+ << (pubRateTotal / opts.iterations) << "\t"
+ << (subRateTotal / opts.iterations) << "\t"
+ << (txrateTotal / opts.iterations) << "\t"
+ << (mbytesTotal / opts.iterations) << endl;
+ }
+ }
+ catch (const std::exception& e) {
+ cout << "Controller exception: " << e.what() << endl;
+ }
+ }
+};
+
+
+struct PublishThread : public Client {
+ string destination;
+ string routingKey;
+
+ PublishThread() {};
+
+ PublishThread(string key, string dest=string()) {
+ destination=dest;
+ routingKey=key;
+ }
+
+ void run() { // Publisher
+ try {
+ string data;
+ size_t offset(0);
+ if (opts.uniqueData) {
+ offset = 5;
+ data += "data:";//marker (requested for latency testing tool scripts)
+ data += string(sizeof(size_t), 'X');//space for seq no
+ data += session.getId().str();
+ if (opts.size > data.size()) {
+ data += string(opts.size - data.size(), 'X');
+ } else if(opts.size < data.size()) {
+ cout << "WARNING: Increased --size to " << data.size()
+ << " to honour --unique-data" << endl;
+ }
+ } else {
+ size_t msgSize=max(opts.size, sizeof(size_t));
+ data = string(msgSize, 'X');
+ }
+
+ Message msg(data, routingKey);
+ if (opts.durable)
+ msg.getDeliveryProperties().setDeliveryMode(framing::PERSISTENT);
+
+
+ if (opts.txPub){
+ session.txSelect();
+ }
+ SubscriptionManager subs(session);
+ LocalQueue lq;
+ subs.setFlowControl(1, SubscriptionManager::UNLIMITED, true);
+ subs.subscribe(lq, "pub_start");
+
+ for (size_t j = 0; j < opts.iterations; ++j) {
+ expect(lq.pop().getData(), "start");
+ AbsTime start=now();
+ for (size_t i=0; i<opts.count; i++) {
+ // Stamp the iteration into the message data, avoid
+ // any heap allocation.
+ const_cast<std::string&>(msg.getData()).replace(offset, sizeof(size_t),
+ reinterpret_cast<const char*>(&i), sizeof(size_t));
+ if (opts.syncPub) {
+ sync(session).messageTransfer(
+ arg::destination=destination,
+ arg::content=msg,
+ arg::acceptMode=1);
+ } else {
+ session.messageTransfer(
+ arg::destination=destination,
+ arg::content=msg,
+ arg::acceptMode=1);
+ }
+ if (opts.txPub && ((i+1) % opts.txPub == 0)){
+ if (opts.commitAsync){
+ session.txCommit();
+ } else {
+ sync(session).txCommit();
+ }
+ }
+ if (opts.intervalPub) ::usleep(opts.intervalPub*1000);
+ }
+ if (opts.confirm) session.sync();
+ AbsTime end=now();
+ double time=secs(start,end);
+
+ // Send result to controller.
+ Message report(lexical_cast<string>(opts.count/time), "pub_done");
+ session.messageTransfer(arg::content=report, arg::acceptMode=1);
+ if (opts.txPub){
+ sync(session).txCommit();
+ }
+ }
+ session.close();
+ }
+ catch (const std::exception& e) {
+ cout << "PublishThread exception: " << e.what() << endl;
+ }
+ }
+};
+
+struct SubscribeThread : public Client {
+
+ string queue;
+
+ SubscribeThread() {}
+
+ SubscribeThread(string q) { queue = q; }
+
+ SubscribeThread(string key, string ex) {
+ queue=session.getId().str(); // Unique name.
+ session.queueDeclare(arg::queue=queue,
+ arg::exclusive=true,
+ arg::autoDelete=true,
+ arg::durable=opts.durable);
+ session.exchangeBind(arg::queue=queue,
+ arg::exchange=ex,
+ arg::bindingKey=key);
+ }
+
+ void verify(bool cond, const char* test, uint32_t expect, uint32_t actual) {
+ if (!cond) {
+ Message error(
+ QPID_MSG("Sequence error: expected n" << test << expect << " but got " << actual),
+ "sub_done");
+ session.messageTransfer(arg::content=error, arg::acceptMode=1);
+ throw Exception(error.getData());
+ }
+ }
+
+ void run() { // Subscribe
+ try {
+ if (opts.txSub) sync(session).txSelect();
+ SubscriptionManager subs(session);
+ SubscriptionSettings settings;
+ settings.autoAck = opts.txSub ? opts.txSub : opts.ack;
+ settings.acceptMode = (opts.txSub || opts.ack ? ACCEPT_MODE_EXPLICIT : ACCEPT_MODE_NONE);
+ settings.flowControl = FlowControl::messageCredit(opts.subQuota);
+ LocalQueue lq;
+ Subscription subscription = subs.subscribe(lq, queue, settings);
+ // Notify controller we are ready.
+ session.messageTransfer(arg::content=Message("ready", "sub_ready"), arg::acceptMode=1);
+ if (opts.txSub) {
+ if (opts.commitAsync) session.txCommit();
+ else sync(session).txCommit();
+ }
+
+ for (size_t j = 0; j < opts.iterations; ++j) {
+ if (j > 0) {
+ //need to allocate some more credit
+ session.messageFlow(queue, 0, opts.subQuota);
+ }
+ Message msg;
+ AbsTime start=now();
+ size_t expect=0;
+ for (size_t i = 0; i < opts.subQuota; ++i) {
+ msg=lq.pop();
+ if (opts.txSub && ((i+1) % opts.txSub == 0)) {
+ if (opts.commitAsync) session.txCommit();
+ else sync(session).txCommit();
+ }
+ if (opts.intervalSub) ::usleep(opts.intervalSub*1000);
+ // TODO aconway 2007-11-23: check message order for.
+ // multiple publishers. Need an array of counters,
+ // one per publisher and a publisher ID in the
+ // message. Careful not to introduce a lot of overhead
+ // here, e.g. no std::map, std::string etc.
+ //
+ // For now verify order only for a single publisher.
+ size_t offset = opts.uniqueData ? 5 /*marker is 'data:'*/ : 0;
+ size_t n = *reinterpret_cast<const size_t*>(msg.getData().data() + offset);
+ if (opts.pubs == 1) {
+ if (opts.subs == 1 || opts.mode == FANOUT) verify(n==expect, "==", expect, n);
+ else verify(n>=expect, ">=", expect, n);
+ expect = n+1;
+ }
+ }
+ if (opts.txSub || opts.ack)
+ subscription.accept(subscription.getUnaccepted());
+ if (opts.txSub) {
+ if (opts.commitAsync) session.txCommit();
+ else sync(session).txCommit();
+ }
+ AbsTime end=now();
+
+ // Report to publisher.
+ Message result(lexical_cast<string>(opts.subQuota/secs(start,end)),
+ "sub_done");
+ session.messageTransfer(arg::content=result, arg::acceptMode=1);
+ if (opts.txSub) sync(session).txCommit();
+ }
+ session.close();
+ }
+ catch (const std::exception& e) {
+ cout << "SubscribeThread exception: " << e.what() << endl;
+ }
+ }
+};
+
+int main(int argc, char** argv) {
+
+ try {
+ opts.parse(argc, argv);
+
+ string exchange;
+ switch (opts.mode) {
+ case FANOUT: exchange="amq.fanout"; break;
+ case TOPIC: exchange="amq.topic"; break;
+ case SHARED: break;
+ }
+
+ bool singleProcess=
+ (!opts.setup && !opts.control && !opts.publish && !opts.subscribe);
+ if (singleProcess)
+ opts.setup = opts.control = opts.publish = opts.subscribe = true;
+
+ if (opts.setup) Setup().run(); // Set up queues
+
+ boost::ptr_vector<Client> subs(opts.subs);
+ boost::ptr_vector<Client> pubs(opts.pubs);
+
+ // Start pubs/subs for each queue/topic.
+ for (size_t i = 0; i < opts.qt; ++i) {
+ ostringstream key;
+ key << "perftest" << i; // Queue or topic name.
+ if (opts.publish) {
+ size_t n = singleProcess ? opts.pubs : 1;
+ for (size_t j = 0; j < n; ++j) {
+ pubs.push_back(new PublishThread(key.str(), exchange));
+ pubs.back().thread=Thread(pubs.back());
+ }
+ }
+ if (opts.subscribe) {
+ size_t n = singleProcess ? opts.subs : 1;
+ for (size_t j = 0; j < n; ++j) {
+ if (opts.mode==SHARED)
+ subs.push_back(new SubscribeThread(key.str()));
+ else
+ subs.push_back(new SubscribeThread(key.str(),exchange));
+ subs.back().thread=Thread(subs.back());
+ }
+ }
+ }
+
+ if (opts.control) Controller().run();
+
+
+ // Wait for started threads.
+ if (opts.publish) {
+ for (boost::ptr_vector<Client>::iterator i=pubs.begin();
+ i != pubs.end();
+ ++i)
+ i->thread.join();
+ }
+
+
+ if (opts.subscribe) {
+ for (boost::ptr_vector<Client>::iterator i=subs.begin();
+ i != subs.end();
+ ++i)
+ i->thread.join();
+ }
+ return 0;
+ }
+ catch (const std::exception& e) {
+ cout << endl << e.what() << endl;
+ }
+ return 1;
+}
+
+
diff --git a/RC9/qpid/cpp/src/tests/policy.acl b/RC9/qpid/cpp/src/tests/policy.acl
new file mode 100644
index 0000000000..ef46026555
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/policy.acl
@@ -0,0 +1 @@
+acl allow all all
diff --git a/RC9/qpid/cpp/src/tests/publish.cpp b/RC9/qpid/cpp/src/tests/publish.cpp
new file mode 100644
index 0000000000..34c2b8fefc
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/publish.cpp
@@ -0,0 +1,128 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <algorithm>
+#include <iostream>
+#include <memory>
+#include <sstream>
+#include <vector>
+
+#include "TestOptions.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/SubscriptionManager.h"
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace qpid::sys;
+using namespace std;
+
+typedef vector<string> StringSet;
+
+struct Args : public qpid::TestOptions {
+ uint size;
+ uint count;
+ bool durable;
+ string destination;
+ string routingKey;
+ bool summary;
+ bool id;
+
+ Args() : size(256), count(1000), durable(true), routingKey("publish-consume"), summary(false), id(false) {
+ addOptions()
+ ("size", optValue(size, "N"), "message size")
+ ("count", optValue(count, "N"), "number of messages to publish")
+ ("durable", optValue(durable, "yes|no"), "use durable messages")
+ ("destination", optValue(destination, "<exchange name>"), "destination to publish to")
+ ("routing-key", optValue(routingKey, "<key>"), "routing key to publish with")
+ ("summary,s", optValue(summary), "Output only the rate.")
+ ("id", optValue(id), "Add unique correlation ID");
+ }
+};
+
+Args opts;
+
+struct Client
+{
+ Connection connection;
+ AsyncSession session;
+
+ Client()
+ {
+ opts.open(connection);
+ session = connection.newSession();
+ }
+
+ // Cheap hex calculation, avoid expensive ostrstream and string
+ // creation to generate correlation ids in message loop.
+ char hex(char i) { return i<10 ? '0'+i : 'A'+i-10; }
+ void hex(char i, string& s) {
+ s[0]=hex(i>>24); s[1]=hex(i>>16); s[2]=hex(i>>8); s[3]=i;
+ }
+
+ void publish()
+ {
+ AbsTime begin=now();
+ Message msg(string(opts.size, 'X'), opts.routingKey);
+ string correlationId = "0000";
+ if (opts.durable)
+ msg.getDeliveryProperties().setDeliveryMode(framing::PERSISTENT);
+
+ for (uint i = 0; i < opts.count; i++) {
+ if (opts.id) {
+ hex(i+1, correlationId);
+ msg.getMessageProperties().setCorrelationId(correlationId);
+ }
+ session.messageTransfer(arg::destination=opts.destination,
+ arg::content=msg,
+ arg::acceptMode=1);
+ }
+ session.sync();
+ AbsTime end=now();
+ double secs(double(Duration(begin,end))/TIME_SEC);
+ if (opts.summary) cout << opts.count/secs << endl;
+ else cout << "Time: " << secs << "s Rate: " << opts.count/secs << endl;
+ }
+
+ ~Client()
+ {
+ try{
+ session.close();
+ connection.close();
+ } catch(const exception& e) {
+ cout << e.what() << endl;
+ }
+ }
+};
+
+int main(int argc, char** argv)
+{
+ try {
+ opts.parse(argc, argv);
+ Client client;
+ client.publish();
+ return 0;
+ } catch(const exception& e) {
+ cout << e.what() << endl;
+ }
+ return 1;
+}
diff --git a/RC9/qpid/cpp/src/tests/python_tests b/RC9/qpid/cpp/src/tests/python_tests
new file mode 100755
index 0000000000..30bb8259a4
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/python_tests
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Run the python tests.
+QPID_PORT=${QPID_PORT:-5672}
+PYTHON_TESTS=${PYTHON_TESTS:-$*}
+MY_DIR=`dirname \`which $0\``
+QPID_PYTHON_DIR=${QPID_PYTHON_DIR:-${MY_DIR}/../../../python}
+
+run() {
+ SPEC=$1
+ FAILING=$2
+ ./run-tests --skip-self-test -v -s $SPEC -I $FAILING -b localhost:$QPID_PORT $PYTHON_TESTS || { echo "FAIL python tests for $SPEC"; exit 1; }
+}
+
+if test -d ${QPID_PYTHON_DIR} ; then
+ cd ${QPID_PYTHON_DIR}
+ run 0-10-errata cpp_failing_0-10.txt
+else
+ echo "WARNING: No python tests. $QPID_PYTHON_DIR not found."
+fi
diff --git a/RC9/qpid/cpp/src/tests/quick_perftest b/RC9/qpid/cpp/src/tests/quick_perftest
new file mode 100755
index 0000000000..4f7cf3cb54
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/quick_perftest
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+exec `dirname $0`/run_test ./perftest --summary --count 100
diff --git a/RC9/qpid/cpp/src/tests/quick_topictest b/RC9/qpid/cpp/src/tests/quick_topictest
new file mode 100755
index 0000000000..5e7d85849f
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/quick_topictest
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+
+# Quick and quiet topic test for make check.
+test -z "$srcdir" && srcdir=.
+$srcdir/topictest -s2 -m2 -b1 > topictest.log 2>&1 || {
+ echo $0 FAILED:
+ cat topictest.log
+ exit 1
+}
+rm topictest.log
diff --git a/RC9/qpid/cpp/src/tests/quick_txtest b/RC9/qpid/cpp/src/tests/quick_txtest
new file mode 100755
index 0000000000..938e3805d8
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/quick_txtest
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+exec `dirname $0`/run_test ./txtest --queues 4 --tx-count 10 --quiet
diff --git a/RC9/qpid/cpp/src/tests/receiver.cpp b/RC9/qpid/cpp/src/tests/receiver.cpp
new file mode 100644
index 0000000000..1b0b6b2548
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/receiver.cpp
@@ -0,0 +1,129 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/client/FailoverManager.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/Message.h>
+#include <qpid/client/SubscriptionManager.h>
+#include <qpid/client/SubscriptionManager.h>
+#include "TestOptions.h"
+
+#include <iostream>
+#include <fstream>
+
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace qpid::framing;
+
+using namespace std;
+
+struct Args : public qpid::TestOptions
+{
+ string queue;
+ uint messages;
+ bool ignoreDuplicates;
+ uint creditWindow;
+ uint ackFrequency;
+
+ Args() : queue("test-queue"), messages(0), ignoreDuplicates(false), creditWindow(0), ackFrequency(1)
+ {
+ addOptions()
+ ("queue", qpid::optValue(queue, "QUEUE NAME"), "Queue from which to request messages")
+ ("messages", qpid::optValue(messages, "N"), "Number of messages to receive; 0 means receive indefinitely")
+ ("ignore-duplicates", qpid::optValue(ignoreDuplicates), "Detect and ignore duplicates (by checking 'sn' header)")
+ ("credit-window", qpid::optValue(creditWindow, "N"), "Credit window (0 implies infinite window)")
+ ("ack-frequency", qpid::optValue(ackFrequency, "N"), "Ack frequency (0 implies none of the messages will get accepted)");
+ }
+};
+
+const string EOS("eos");
+
+class Receiver : public MessageListener, public FailoverManager::Command
+{
+ public:
+ Receiver(const string& queue, uint messages, bool ignoreDuplicates, uint creditWindow, uint ackFrequency);
+ void received(Message& message);
+ void execute(AsyncSession& session, bool isRetry);
+ private:
+ const string queue;
+ const uint count;
+ const bool skipDups;
+ SubscriptionSettings settings;
+ Subscription subscription;
+ uint processed;
+ uint lastSn;
+
+ bool isDuplicate(Message& message);
+};
+
+Receiver::Receiver(const string& q, uint messages, bool ignoreDuplicates, uint creditWindow, uint ackFrequency) :
+ queue(q), count(messages), skipDups(ignoreDuplicates), processed(0), lastSn(0)
+{
+ if (creditWindow) settings.flowControl = FlowControl::messageWindow(creditWindow);
+ settings.autoAck = ackFrequency;
+}
+
+void Receiver::received(Message & message)
+{
+ if (!(skipDups && isDuplicate(message))) {
+ bool eos = message.getData() == EOS;
+ if (!eos) std::cout << message.getData() << std::endl;
+ if (eos || ++processed == count) subscription.cancel();
+ }
+}
+
+bool Receiver::isDuplicate(Message& message)
+{
+ uint sn = message.getHeaders().getAsInt("sn");
+ if (lastSn < sn) {
+ lastSn = sn;
+ return false;
+ } else {
+ return true;
+ }
+}
+
+void Receiver::execute(AsyncSession& session, bool /*isRetry*/)
+{
+ SubscriptionManager subs(session);
+ subscription = subs.subscribe(*this, queue, settings);
+ subs.run();
+}
+
+int main(int argc, char ** argv)
+{
+ Args opts;
+ try {
+ opts.parse(argc, argv);
+ FailoverManager connection(opts.con);
+ Receiver receiver(opts.queue, opts.messages, opts.ignoreDuplicates, opts.creditWindow, opts.ackFrequency);
+ connection.execute(receiver);
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cerr << "Failure: " << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
+
diff --git a/RC9/qpid/cpp/src/tests/replaying_sender.cpp b/RC9/qpid/cpp/src/tests/replaying_sender.cpp
new file mode 100644
index 0000000000..7e148e277f
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/replaying_sender.cpp
@@ -0,0 +1,131 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/client/FailoverManager.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/AsyncSession.h>
+#include <qpid/client/Message.h>
+#include <qpid/client/MessageReplayTracker.h>
+#include <qpid/Exception.h>
+
+#include <iostream>
+#include <sstream>
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace qpid::framing;
+
+using namespace std;
+
+class Sender : public FailoverManager::Command
+{
+ public:
+ Sender(const std::string& queue, uint count, uint reportFreq);
+ void execute(AsyncSession& session, bool isRetry);
+ uint getSent();
+
+ int verbosity;
+
+ private:
+ MessageReplayTracker sender;
+ const uint count;
+ uint sent;
+ const uint reportFrequency;
+ Message message;
+
+};
+
+Sender::Sender(const std::string& queue, uint count_, uint reportFreq ) : sender(10), count(count_), sent(0), reportFrequency(reportFreq)
+{
+ message.getDeliveryProperties().setRoutingKey(queue);
+}
+
+void Sender::execute(AsyncSession& session, bool isRetry)
+{
+ if (isRetry) sender.replay(session);
+ else sender.init(session);
+ while (sent < count) {
+ stringstream message_data;
+ message_data << ++sent;
+ message.setData(message_data.str());
+ message.getHeaders().setInt("sn", sent);
+ sender.send(message);
+ if (count > reportFrequency && !(sent % reportFrequency)) {
+ if ( verbosity > 0 )
+ std::cout << "sent " << sent << " of " << count << std::endl;
+ }
+ }
+ message.setData("That's all, folks!");
+ sender.send(message);
+
+ if ( verbosity > 0 )
+ std::cout << "SENDER COMPLETED\n";
+}
+
+uint Sender::getSent()
+{
+ return sent;
+}
+
+int main(int argc, char ** argv)
+{
+ ConnectionSettings settings;
+
+ if ( argc != 6 )
+ {
+ std::cerr << "Usage: replaying_sender host port n_messages report_frequency verbosity\n";
+ return 1;
+ }
+
+ settings.host = argv[1];
+ settings.port = atoi(argv[2]);
+ int n_messages = atoi(argv[3]);
+ int reportFrequency = atoi(argv[4]);
+ int verbosity = atoi(argv[5]);
+
+ FailoverManager connection(settings);
+ Sender sender("message_queue", n_messages, reportFrequency );
+ sender.verbosity = verbosity;
+ try {
+ connection.execute ( sender );
+ if ( verbosity > 0 )
+ {
+ std::cout << "Sender finished. Sent "
+ << sender.getSent()
+ << " messages."
+ << endl;
+ }
+ connection.close();
+ return 0;
+ }
+ catch(const std::exception& error)
+ {
+ cerr << "Sender (host: "
+ << settings.host
+ << " port: "
+ << settings.port
+ << " ) "
+ << " Failed: "
+ << error.what()
+ << std::endl;
+ }
+ return 1;
+}
diff --git a/RC9/qpid/cpp/src/tests/restart_cluster b/RC9/qpid/cpp/src/tests/restart_cluster
new file mode 100755
index 0000000000..6a6abc8042
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/restart_cluster
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Re-start a cluster on the local host.
+
+srcdir=`dirname $0`
+$srcdir/stop_cluster
+exec $srcdir/start_cluster "$@"
+#!/bin/sh
+# Re-start a cluster on the local host.
+
+srcdir=`dirname $0`
+$srcdir/stop_cluster
+exec $srcdir/start_cluster "$@"
+#!/bin/sh
+# Re-start a cluster on the local host.
+
+srcdir=`dirname $0`
+$srcdir/stop_cluster
+exec $srcdir/start_cluster "$@"
diff --git a/RC9/qpid/cpp/src/tests/resuming_receiver.cpp b/RC9/qpid/cpp/src/tests/resuming_receiver.cpp
new file mode 100644
index 0000000000..f49a115e1e
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/resuming_receiver.cpp
@@ -0,0 +1,163 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/client/FailoverManager.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/Message.h>
+#include <qpid/client/SubscriptionManager.h>
+
+#include <iostream>
+#include <fstream>
+
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace qpid::framing;
+
+using namespace std;
+
+
+class Listener : public MessageListener,
+ public FailoverManager::Command,
+ public FailoverManager::ReconnectionStrategy
+{
+ public:
+ Listener ( int report_frequency = 1000, int verbosity = 0 );
+ void received(Message& message);
+ void execute(AsyncSession& session, bool isRetry);
+ void check();
+ void editUrlList(std::vector<Url>& urls);
+ private:
+ Subscription subscription;
+ uint count;
+ uint received_twice;
+ uint lastSn;
+ bool gaps;
+ uint reportFrequency;
+ int verbosity;
+};
+
+
+Listener::Listener(int freq, int verbosity)
+ : count(0),
+ received_twice(0),
+ lastSn(0),
+ gaps(false),
+ reportFrequency(freq),
+ verbosity(verbosity)
+{}
+
+
+void Listener::received(Message & message)
+{
+ if (message.getData() == "That's all, folks!")
+ {
+ if(verbosity > 0 )
+ {
+ std::cout << "Shutting down listener for "
+ << message.getDestination() << std::endl;
+
+ std::cout << "Listener received "
+ << count
+ << " messages ("
+ << received_twice
+ << " received_twice)"
+ << endl;
+ }
+ subscription.cancel();
+ if ( verbosity > 0 )
+ std::cout << "LISTENER COMPLETED\n";
+ } else {
+ uint sn = message.getHeaders().getAsInt("sn");
+ if (lastSn < sn) {
+ if (sn - lastSn > 1) {
+ std::cerr << "Error: gap in sequence between " << lastSn << " and " << sn << std::endl;
+ gaps = true;
+ }
+ lastSn = sn;
+ ++count;
+ if ( ! ( count % reportFrequency ) ) {
+ if ( verbosity > 0 )
+ std::cout << "Listener has received "
+ << count
+ << " messages.\n";
+ }
+ } else {
+ ++received_twice;
+ }
+ }
+}
+
+void Listener::check()
+{
+ if (gaps) throw Exception("Detected gaps in sequence; messages appear to have been lost.");
+}
+
+void Listener::execute(AsyncSession& session, bool isRetry)
+{
+ if (isRetry) {
+ // std::cout << "Resuming from " << count << std::endl;
+ }
+ SubscriptionManager subs(session);
+ subscription = subs.subscribe(*this, "message_queue");
+ subs.run();
+}
+
+void Listener::editUrlList(std::vector<Url>& urls)
+{
+ /**
+ * A more realistic algorithm would be to search through the list
+ * for prefered hosts and ensure they come first in the list.
+ */
+ if (urls.size() > 1) std::rotate(urls.begin(), urls.begin() + 1, urls.end());
+}
+
+int main(int argc, char ** argv)
+{
+ ConnectionSettings settings;
+
+ if ( argc != 5 )
+ {
+ std::cerr << "Usage: resuming_receiver host port report_frequency verbosity\n";
+ return 1;
+ }
+
+ settings.host = argv[1];
+ settings.port = atoi(argv[2]);
+ int reportFrequency = atoi(argv[3]);
+ int verbosity = atoi(argv[4]);
+
+ Listener listener(reportFrequency, verbosity);
+ FailoverManager connection(settings, &listener);
+
+ try {
+ connection.execute(listener);
+ connection.close();
+ listener.check();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cerr << "Receiver failed: " << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
+
diff --git a/RC9/qpid/cpp/src/tests/run-unit-tests b/RC9/qpid/cpp/src/tests/run-unit-tests
new file mode 100755
index 0000000000..862a76c4f5
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/run-unit-tests
@@ -0,0 +1,48 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#
+# Library names (without path or .so) and CppUnit test paths can be
+# specified on the command line or in env var UNIT_TESTS. For example:
+#
+# Selected test classes:
+# ./run-unit-tests ValueTest ClientChannelTest
+#
+# Individual test method
+# ./run-unit-tests ValueTest :ValueTest::testStringValueEquals
+#
+# Build and run selected tests:
+# make check TESTS=run-unit-tests UNIT_TESTS=ClientChannelTest
+#
+
+for u in $* $UNIT_TESTS ; do
+ case $u in
+ :*) TEST_ARGS="$TEST_ARGS $u" ;; # A test path.
+ *) TEST_ARGS="$TEST_ARGS .libs/$u.so" ;; # A test library.
+ esac
+done
+test -z "$TEST_ARGS" && TEST_ARGS=".libs/*Test.so"
+
+test -z "$srcdir" && srcdir=.
+
+# libdlclose_noop prevents unloading symbols needed for valgrind output.
+export LD_PRELOAD=.libs/libdlclose_noop.so
+source $srcdir/run_test DllPlugInTester -c -b $TEST_ARGS
diff --git a/RC9/qpid/cpp/src/tests/run_acl_tests b/RC9/qpid/cpp/src/tests/run_acl_tests
new file mode 100755
index 0000000000..8d583c1895
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/run_acl_tests
@@ -0,0 +1,64 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Run the acl tests. $srcdir is set by the Makefile.
+PYTHON_DIR=$srcdir/../../../python
+DATA_DIR=`pwd`/data_dir
+
+trap stop_brokers INT TERM QUIT
+
+start_brokers() {
+ ../qpidd --daemon --port 0 --no-module-dir --data-dir $DATA_DIR --load-module ../.libs/acl.so --acl-file policy.acl --auth no > qpidd.port
+ LOCAL_PORT=`cat qpidd.port`
+}
+
+stop_brokers() {
+ ../qpidd -q --port $LOCAL_PORT
+}
+
+test_loading_acl_from_absolute_path(){
+ POLICY_FILE=$PWD/$srcdir/policy.acl
+ ../qpidd --daemon --port 0 --no-module-dir --no-data-dir --auth no --load-module ../.libs/acl.so --acl-file $POLICY_FILE -t --log-to-file temp.log 2>/dev/null
+ PORT=`grep "Listening on TCP port" temp.log | awk '{print $8}'`
+ ACL_FILE=`grep "notice Read ACL file" temp.log | awk '{print $7}'`
+ ../qpidd -q --port $PORT
+ if test "$ACL_FILE" != "\"$POLICY_FILE\""; then
+ echo "unable to load policy file from an absolute path";
+ return 1;
+ fi
+ rm temp.log
+}
+
+if test -d ${PYTHON_DIR} ; then
+ rm -rf $DATA_DIR
+ mkdir -p $DATA_DIR
+ cp $srcdir/policy.acl $DATA_DIR
+ start_brokers
+ echo "Running acl tests using brokers on ports $LOCAL_PORT"
+ PYTHONPATH=$PYTHON_DIR
+ export PYTHONPATH
+ $srcdir/acl.py -v -s $srcdir/../../../specs/amqp.0-10-qpid-errata.xml -b localhost:$LOCAL_PORT --port $LOCAL_PORT || EXITCODE=1
+ stop_brokers || EXITCODE=1
+ test_loading_acl_from_absolute_path || EXITCODE=1
+ rm -rf $DATA_DIR
+ exit $EXITCODE
+fi
+
diff --git a/RC9/qpid/cpp/src/tests/run_failover_soak b/RC9/qpid/cpp/src/tests/run_failover_soak
new file mode 100755
index 0000000000..9dddf59cf1
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/run_failover_soak
@@ -0,0 +1,56 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Check AIS requirements and run tests if found.
+id -ng | grep '\<ais\>' >/dev/null || \
+ NOGROUP="The ais group is not your primary group."
+ps -u root | grep aisexec >/dev/null || \
+ NOAISEXEC="The aisexec daemon is not running as root"
+
+if test -n "$NOGROUP" -o -n "$NOAISEXEC"; then
+ cat <<EOF
+
+ =========== WARNING: NOT RUNNING AIS TESTS ==============
+
+ Tests that depend on the openais library (used for clustering)
+ will not be run because:
+
+ $NOGROUP
+ $NOAISEXEC
+
+ ==========================================================
+
+EOF
+ exit 0; # A warning, not a failure.
+fi
+
+
+host=127.0.0.1
+
+src_root=..
+module_dir=$src_root/.libs
+n_messages=300000
+report_frequency=10000
+verbosity=1
+
+
+exec `dirname $0`/failover_soak $src_root $module_dir $host ./declare_queues ./replaying_sender ./resuming_receiver $n_messages $report_frequency $verbosity
+
diff --git a/RC9/qpid/cpp/src/tests/run_federation_tests b/RC9/qpid/cpp/src/tests/run_federation_tests
new file mode 100755
index 0000000000..28bcc012cc
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/run_federation_tests
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Run the federation tests.
+MY_DIR=`dirname \`which $0\``
+PYTHON_DIR=${MY_DIR}/../../../python
+
+trap stop_brokers INT TERM QUIT
+
+start_brokers() {
+ ../qpidd --daemon --port 0 --no-data-dir --no-module-dir --auth no > qpidd.port
+ LOCAL_PORT=`cat qpidd.port`
+ ../qpidd --daemon --port 0 --no-data-dir --no-module-dir --auth no > qpidd.port
+ REMOTE_PORT=`cat qpidd.port`
+}
+
+stop_brokers() {
+ ../qpidd -q --port $LOCAL_PORT
+ ../qpidd -q --port $REMOTE_PORT
+}
+
+if test -d ${PYTHON_DIR} ; then
+ start_brokers
+ echo "Running federation tests using brokers on ports $LOCAL_PORT $REMOTE_PORT"
+ PYTHONPATH=${PYTHON_DIR}
+ export PYTHONPATH
+ ${MY_DIR}/federation.py -v -s ${MY_DIR}/../../../specs/amqp.0-10-qpid-errata.xml -b localhost:$LOCAL_PORT --remote-port $REMOTE_PORT $@
+ RETCODE=$?
+ stop_brokers
+ if test x$RETCODE != x0; then
+ echo "FAIL federation tests"; exit 1;
+ fi
+fi
+
diff --git a/RC9/qpid/cpp/src/tests/run_header_test b/RC9/qpid/cpp/src/tests/run_header_test
new file mode 100755
index 0000000000..39d4a24f84
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/run_header_test
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Simple test of encode/decode of a double in application headers
+# TODO: this should be expanded to cover a wider set of types and go
+# in both directions
+
+srcdir=`dirname $0`
+PYTHON_DIR=$srcdir/../../../python
+test -f qpidd.port && QPID_PORT=`cat qpidd.port`
+
+if test -d ${PYTHON_DIR} ; then
+ ./header_test -p $QPID_PORT
+ export PYTHONPATH=$PYTHON_DIR:$PYTHONPATH
+ $srcdir/header_test.py "localhost" $QPID_PORT
+else
+ echo "Skipping header test as python libs not found"
+fi
+
diff --git a/RC9/qpid/cpp/src/tests/run_perftest b/RC9/qpid/cpp/src/tests/run_perftest
new file mode 100755
index 0000000000..1a9b934641
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/run_perftest
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Args: count [perftest options...]
+# Run a perftest with count multiplied.
+#
+MULTIPLIER=3
+COUNT=`expr $1 \* $MULTIPLIER`
+shift
+exec `dirname $0`/run_test ./perftest --summary --count $COUNT "$@"
diff --git a/RC9/qpid/cpp/src/tests/run_test b/RC9/qpid/cpp/src/tests/run_test
new file mode 100755
index 0000000000..062e9e137e
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/run_test
@@ -0,0 +1,78 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#
+# Set up environment and run a test executable or script.
+#
+# Output nothing if test passes, show the output if it fails and
+# leave output in <test>.log for examination.
+#
+# If qpidd.port exists run test with QPID_PORT=`cat qpidd.port`
+#
+# If $VALGRIND if is set run under valgrind. If there are valgrind
+# erros show valgrind output, also leave it in <test>.valgrind for
+# examination.
+#
+
+srcdir=`dirname $0`
+. $srcdir/vg_check
+
+# Export variables from makefile.
+export VALGRIND srcdir
+
+# Set QPID_PORT if qpidd.port exists.
+test -f qpidd.port && QPID_PORT=`cat qpidd.port`
+export QPID_PORT
+
+# Avoid silly libtool error messages if these are not defined
+test -z "$LC_ALL" && LC_ALL=
+test -z "$LC_CTYPE" && LC_CTYPE=
+test -z "$LC_COLLATE" && LC_COLLATE=
+test -z "$LC_MESSAGES" && LC_MESSAGES=
+export LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+
+VG_LOG="`basename $1`.vglog"
+rm -f $VG_LOG*
+
+VALGRIND_OPTS="
+--gen-suppressions=all
+--leak-check=full
+--demangle=yes
+--suppressions=$srcdir/.valgrind.supp
+--num-callers=25
+--log-file=$VG_LOG --
+"
+# FIXME aconway 2008-07-16: removed --trace-children=yes, problems with cluster tests forking
+# qpidd libtool script. Investigate & restore --trace-children if possible.
+
+ERROR=0
+if grep -l "^# Generated by .*libtool" "$1" >/dev/null 2>&1; then
+ # This is a libtool "executable". Valgrind it if VALGRIND specified.
+ test -n "$VALGRIND" && VALGRIND="$VALGRIND $VALGRIND_OPTS"
+ # Hide output unless there's an error.
+ libtool --mode=execute $VALGRIND "$@" 2>&1 || ERROR=1
+ test -n "$VALGRIND" && { vg_check $VG_LOG* || ERROR=1 ; }
+else
+ # This is a non-libtool shell script, just execute it.
+ exec "$@"
+fi
+
+exit $ERROR
+
diff --git a/RC9/qpid/cpp/src/tests/sender.cpp b/RC9/qpid/cpp/src/tests/sender.cpp
new file mode 100644
index 0000000000..a02b713d86
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/sender.cpp
@@ -0,0 +1,100 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/client/FailoverManager.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/AsyncSession.h>
+#include <qpid/client/Message.h>
+#include <qpid/client/MessageReplayTracker.h>
+#include <qpid/Exception.h>
+#include "TestOptions.h"
+
+#include <iostream>
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace qpid::framing;
+
+using namespace std;
+
+struct Args : public qpid::TestOptions
+{
+ string destination;
+ string key;
+ uint sendEos;
+
+ Args() : key("test-queue"), sendEos(0)
+ {
+ addOptions()
+ ("exchange", qpid::optValue(destination, "EXCHANGE"), "Exchange to send messages to")
+ ("routing-key", qpid::optValue(key, "KEY"), "Routing key to add to messages")
+ ("send-eos", qpid::optValue(sendEos, "N"), "Send N EOS messages to mark end of input");
+ }
+};
+
+const string EOS("eos");
+
+class Sender : public FailoverManager::Command
+{
+ public:
+ Sender(const std::string& destination, const std::string& key, uint sendEos);
+ void execute(AsyncSession& session, bool isRetry);
+ private:
+ MessageReplayTracker sender;
+ Message message;
+ const uint sendEos;
+ uint sent;
+};
+
+Sender::Sender(const std::string& destination, const std::string& key, uint eos) :
+ sender(10), message(destination, key), sendEos(eos), sent(0) {}
+
+void Sender::execute(AsyncSession& session, bool isRetry)
+{
+ if (isRetry) sender.replay(session);
+ else sender.init(session);
+ string data;
+ while (std::cin >> data) {
+ message.setData(data);
+ message.getHeaders().setInt("sn", ++sent);
+ sender.send(message);
+ }
+ for (uint i = sendEos; i > 0; --i) {
+ message.setData(EOS);
+ sender.send(message);
+ }
+}
+
+int main(int argc, char ** argv)
+{
+ Args opts;
+ try {
+ opts.parse(argc, argv);
+ FailoverManager connection(opts.con);
+ Sender sender(opts.destination, opts.key, opts.sendEos);
+ connection.execute(sender);
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << "Failed: " << error.what() << std::endl;
+ }
+ return 1;
+}
diff --git a/RC9/qpid/cpp/src/tests/shared_perftest b/RC9/qpid/cpp/src/tests/shared_perftest
new file mode 100755
index 0000000000..cc192d25bd
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/shared_perftest
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+exec `dirname $0`/run_perftest 100000 --mode shared --npubs 16 --nsubs 16
diff --git a/RC9/qpid/cpp/src/tests/shlibtest.cpp b/RC9/qpid/cpp/src/tests/shlibtest.cpp
new file mode 100644
index 0000000000..80320ea7be
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/shlibtest.cpp
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+int* loaderData = 0;
+extern "C" void callMe(int *i) { loaderData=i; }
+
+struct OnUnload { ~OnUnload() { *loaderData=42; } };
+OnUnload unloader; // For destructor.
+
+
+
diff --git a/RC9/qpid/cpp/src/tests/ssl.mk b/RC9/qpid/cpp/src/tests/ssl.mk
new file mode 100644
index 0000000000..cb887c8fda
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/ssl.mk
@@ -0,0 +1,23 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+TESTS+=ssl_test
+EXTRA_DIST+=ssl_test
+clean-local:
+ rm -rf test_cert_db cert.password \ No newline at end of file
diff --git a/RC9/qpid/cpp/src/tests/ssl_test b/RC9/qpid/cpp/src/tests/ssl_test
new file mode 100755
index 0000000000..047db93d20
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/ssl_test
@@ -0,0 +1,71 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Run a simple test over SSL
+
+CONFIG=$(dirname $0)/config.null
+CERT_DIR=`pwd`/test_cert_db
+CERT_PW_FILE=`pwd`/cert.password
+HOSTNAME=`hostname`
+COUNT=10000
+
+trap stop_broker EXIT
+
+error() { echo $*; exit 1; }
+
+create_certs() {
+ #create certificate and key databases with single, simple, self-signed certificate in it
+ mkdir ${CERT_DIR}
+ certutil -N -d ${CERT_DIR} -f ${CERT_PW_FILE}
+ certutil -S -d ${CERT_DIR} -n ${HOSTNAME} -s "CN=${HOSTNAME}" -t "CT,," -x -f ${CERT_PW_FILE} -z /usr/bin/certutil
+}
+
+start_broker() {
+ ../qpidd --daemon --transport ssl --port 0 --ssl-port 0 --no-data-dir --no-module-dir --auth no --config $CONFIG --load-module ../.libs/ssl.so --ssl-cert-db $CERT_DIR --ssl-cert-password-file $CERT_PW_FILE > qpidd.port
+ PORT=`cat qpidd.port`
+}
+
+stop_broker() {
+ if [[ $PORT ]] ; then
+ ../qpidd -q --port $PORT
+ fi
+}
+CERTUTIL=$(type -p certutil)
+if [[ !(-x $CERTUTIL) ]] ; then
+ echo "No certutil, skipping ssl test";
+ exit 0;
+fi
+
+if [[ !(-e ${CERT_PW_FILE}) ]] ; then
+ echo password > ${CERT_PW_FILE}
+fi
+if [[ !(-e ${CERT_DIR}) ]] ; then
+ create_certs || error "Could not create test certificate"
+fi
+
+start_broker || error "Could not start broker"
+echo "Running SSL test on port $PORT"
+export QPID_NO_MODULE_DIR=1
+export QPID_LOAD_MODULE=../.libs/sslconnector.so
+export QPID_SSL_CERT_DB=${CERT_DIR}
+export QPID_SSL_CERT_PASSWORD_FILE=${CERT_PW_FILE}
+./perftest --count ${COUNT} --port ${PORT} -P ssl -b $HOSTNAME --summary
+
diff --git a/RC9/qpid/cpp/src/tests/start_broker b/RC9/qpid/cpp/src/tests/start_broker
new file mode 100755
index 0000000000..093c44051a
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/start_broker
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Start a test broker.
+srcdir=`dirname $0`
+exec $srcdir/run_test ../qpidd --auth=no --no-module-dir --daemon --port=0 --log-to-file qpidd.log "$@" > qpidd.port
diff --git a/RC9/qpid/cpp/src/tests/start_cluster b/RC9/qpid/cpp/src/tests/start_cluster
new file mode 100755
index 0000000000..ee306edf14
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/start_cluster
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Start a cluster of brokers on local host, put the list of ports for cluster members in cluster.ports
+#
+
+# Execute command with the ais group set.
+with_ais_group() {
+ id -nG | grep '\<ais\>' >/dev/null || { echo "You are not a member of the ais group." 1>&2; exit 1; }
+ echo $* | newgrp ais
+}
+
+test -f cluster.ports && { echo "cluster.ports file already exists" ; exit 1; }
+rm -f cluster*.log
+SIZE=$1; shift
+CLUSTER=`pwd` # Cluster name=pwd, avoid clashes.
+OPTS="-d --load-module ../.libs/cluster.so --cluster-name=$CLUSTER --no-data-dir --auth=no $*"
+
+if test "$SIZE" = "one"; then # Special case of singleton cluster, use default port.
+ ../qpidd -q
+ with_ais_group ../qpidd $OPTS --log-to-file=cluster.log || exit 1
+else
+ for (( i=0; i<SIZE; ++i )); do
+ PORT=`with_ais_group ../qpidd -p0 --log-to-file=cluster$i.log $OPTS` || exit 1
+ echo $PORT >> cluster.ports
+ done
+fi
+
diff --git a/RC9/qpid/cpp/src/tests/start_cluster_hosts b/RC9/qpid/cpp/src/tests/start_cluster_hosts
new file mode 100755
index 0000000000..7680da01ad
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/start_cluster_hosts
@@ -0,0 +1,70 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#
+# Start a cluster of brokers on local host, put the list of host port addresses
+# in cluster.ports
+#
+# Arguments: [-k] [-p port] HOST [HOST...]
+# -p port to start broker on, can be 0. Actual ports recorded in cluster.addr.
+# -k kill any qpidd processes owned by this user before starting.
+#
+# Start a broker on each named host. Name a host twice to start multiple brokers.
+#
+# You must be able to ssh to each host and be in group ais.
+# $QPIDD must be executable on each host.
+# Logs go to syslog on each host, with a unique prefix per broker.
+#
+
+QPIDD=${QPIDD:-$PWD/../qpidd}
+LIBQPIDCLUSTER=${LIBQPIDCLUSTER:-$PWD/../.libs/cluster.so}
+NAME=$USER # User name is default cluster name.
+RESTART=NO
+
+while getopts "kp:n:q:r" ARG ; do
+ case $ARG in
+ k) KILL=yes ;;
+ p) PORT="$OPTARG" ;;
+ n) NAME=$OPTARG ;;
+ q) QPIDD=$OPTARG ;;
+ l) LIBQPIDCLUSTER=$OPTARG ;;
+ r) RESTART=yes ;;
+ *) echo "Error parsing options: $ARG"; exit 1 ;;
+ esac
+done
+shift `expr $OPTIND - 1`
+test -n "$PORT" && PORTOPT="-p $PORT"
+test "$KILL" = yes && KILL="$QPIDD -q $PORTOPT ;"
+CLUSTER=${*:-$CLUSTER} # Use args or env
+test -z "$CLUSTER" && { echo Must specify at least one host; exit 1; }
+
+
+OPTS="-d $PORTOPT --load-module $LIBQPIDCLUSTER --cluster-name=$NAME --no-data-dir --auth=no --log-to-syslog --log-enable=info+"
+
+num=0
+for h in $CLUSTER; do
+ num=`expr $num + 1` # Give a unique log prefix to each node.
+ cmd="$KILL $QPIDD $OPTS --log-prefix $num.$h"
+ out=`echo "$cmd" | ssh $h newgrp ais` || { echo == $h error: $out ; exit 1; }
+ if [ "$PORT" = 0 ] ; then p=$out; else p=$PORT; fi
+ echo "$h $p"
+done
+
diff --git a/RC9/qpid/cpp/src/tests/stop_broker b/RC9/qpid/cpp/src/tests/stop_broker
new file mode 100755
index 0000000000..2f45309a2b
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/stop_broker
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Stop the broker, check for errors.
+#
+QPID_PORT=`cat qpidd.port`
+export QPID_PORT
+rm -f qpidd.port
+
+../qpidd --quit || ERROR=1
+
+# Check qpidd.log.
+egrep 'warning\|error\|critical' qpidd.log && {
+ echo "WARNING: Suspicious broker log entries in qpidd.log, above."
+}
+
+# Check valgrind log.
+if test -n "$VALGRIND"; then
+ . `dirname $0`/vg_check $VG_LOG*
+ vg_check qpidd.vglog* || ERROR=1
+fi
+
+exit $ERROR
diff --git a/RC9/qpid/cpp/src/tests/stop_cluster b/RC9/qpid/cpp/src/tests/stop_cluster
new file mode 100755
index 0000000000..b3f0e7395e
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/stop_cluster
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Stop brokers on ports listed in cluster.ports
+
+PORTS=`cat cluster.ports`
+for PORT in $PORTS ; do
+ ../qpidd -qp $PORT || ERROR="$ERROR $PORT"
+done
+rm -f cluster.ports
+
+if [ -n "$ERROR" ]; then
+ echo "Errors stopping brokers on ports: $ERROR"
+ exit 1
+fi
diff --git a/RC9/qpid/cpp/src/tests/test_tools.h b/RC9/qpid/cpp/src/tests/test_tools.h
new file mode 100644
index 0000000000..37a6594f8a
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/test_tools.h
@@ -0,0 +1,94 @@
+#ifndef TEST_TOOLS_H
+#define TEST_TOOLS_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "qpid/log/Logger.h"
+
+#include <limits.h> // Include before boost/test headers.
+#include <boost/test/test_tools.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/regex.hpp>
+#include <boost/assign/list_of.hpp>
+#include <vector>
+#include <ostream>
+
+// Print a sequence
+template <class T> std::ostream& seqPrint(std::ostream& o, const T& seq) {
+ std::copy(seq.begin(), seq.end(), std::ostream_iterator<typename T::value_type>(o, " "));
+ return o;
+}
+
+// Compare sequences
+template <class T, class U>
+bool seqEqual(const T& a, const U& b) {
+ typename T::const_iterator i = a.begin();
+ typename U::const_iterator j = b.begin();
+ while (i != a.end() && j != b.end() && *i == *j) { ++i; ++j; }
+ return (i == a.end()) && (j == b.end());
+}
+
+// ostream and == operators so we can compare vectors and boost::assign::list_of
+// with BOOST_CHECK_EQUALS
+namespace std { // In namespace std so boost can find them.
+
+template <class T>
+ostream& operator<<(ostream& o, const vector<T>& v) { return seqPrint(o, v); }
+
+template <class T>
+ostream& operator<<(ostream& o, const boost::assign_detail::generic_list<T>& l) { return seqPrint(o, l); }
+
+template <class T>
+bool operator == (const vector<T>& a, const boost::assign_detail::generic_list<T>& b) { return seqEqual(a, b); }
+
+template <class T>
+bool operator == (const boost::assign_detail::generic_list<T>& b, const vector<T>& a) { return seqEqual(a, b); }
+}
+
+/** NB: order of parameters is regex first, in line with
+ * CHECK(expected, actual) convention.
+ */
+inline bool regexPredicate(const std::string& re, const std::string& text) {
+ return boost::regex_match(text, boost::regex(re));
+}
+
+/** Check for regular expression match. You must #include <boost/regex.hpp> */
+#if (BOOST_VERSION < 103300)
+ #define BOOST_CHECK_REGEX(re, text)
+#else
+ #define BOOST_CHECK_REGEX(re, text) \
+ BOOST_CHECK_PREDICATE(regexPredicate, (re)(text))
+#endif
+
+/** Check if types of two objects (as given by typeinfo::name()) match. */
+#define BOOST_CHECK_TYPEID_EQUAL(a,b) BOOST_CHECK_EQUAL(typeid(a).name(),typeid(b).name())
+
+/**
+ * Supress all logging in a scope, restore to previous configuration in destructor.
+ */
+struct ScopedSuppressLogging {
+ typedef qpid::log::Logger Logger;
+ ScopedSuppressLogging(Logger& l=Logger::instance()) : logger(l), opts(l.getOptions()) { l.clear(); }
+ ~ScopedSuppressLogging() { logger.configure(opts); }
+ Logger& logger;
+ qpid::log::Options opts;
+};
+
+
+#endif /*!TEST_TOOLS_H*/
+
diff --git a/RC9/qpid/cpp/src/tests/topic_listener.cpp b/RC9/qpid/cpp/src/tests/topic_listener.cpp
new file mode 100644
index 0000000000..7bdc2c32de
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/topic_listener.cpp
@@ -0,0 +1,202 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/**
+ * This file provides one half of a test and example of a pub-sub
+ * style of interaction. See topic_publisher.cpp for the other half,
+ * in which the logic for publishing is defined.
+ *
+ * This file contains the listener logic. A listener will subscribe to
+ * a logical 'topic'. It will count the number of messages it receives
+ * and the time elapsed between the first one and the last one. It
+ * recognises two types of 'special' message that tell it to (a) send
+ * a report containing this information, (b) shutdown (i.e. stop
+ * listening).
+ */
+
+#include "TestOptions.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/MessageListener.h"
+#include "qpid/client/Session.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/sys/Time.h"
+#include "qpid/framing/FieldValue.h"
+#include <iostream>
+#include <sstream>
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace qpid::sys;
+using namespace qpid::framing;
+using namespace std;
+
+/**
+ * A message listener implementation in which the runtime logic is
+ * defined.
+ */
+class Listener : public MessageListener{
+ Session session;
+ SubscriptionManager& mgr;
+ const string responseQueue;
+ const bool transactional;
+ bool init;
+ int count;
+ AbsTime start;
+
+ void shutdown();
+ void report();
+public:
+ Listener(const Session& session, SubscriptionManager& mgr, const string& reponseQueue, bool tx);
+ virtual void received(Message& msg);
+ Subscription subscription;
+};
+
+/**
+ * A utility class for managing the options passed in.
+ */
+struct Args : public qpid::TestOptions {
+ int ack;
+ bool transactional;
+ bool durable;
+ int prefetch;
+ string statusqueue;
+
+ Args() : ack(0), transactional(false), durable(false), prefetch(0) {
+ addOptions()
+ ("ack", optValue(ack, "MODE"), "Ack frequency in messages (defaults to half the prefetch value)")
+ ("transactional", optValue(transactional), "Use transactions")
+ ("durable", optValue(durable), "subscribers should use durable queues")
+ ("prefetch", optValue(prefetch, "N"), "prefetch count (0 implies no flow control, and no acking)")
+ ("status-queue", optValue(statusqueue, "QUEUE-NAME"), "Message queue to put status messages on");
+ }
+};
+
+
+/**
+ * The main routine creates a Listener instance and sets it up to
+ * consume from a private queue bound to the exchange with the
+ * appropriate topic name.
+ */
+int main(int argc, char** argv){
+ try{
+ Args args;
+ args.parse(argc, argv);
+ if(args.help)
+ cout << args << endl;
+ else {
+ Connection connection;
+ args.open(connection);
+ AsyncSession session = connection.newSession();
+
+ //declare exchange, queue and bind them:
+ session.queueDeclare(arg::queue="response");
+ std::string control = "control_" + session.getId().str();
+ if (args.durable) {
+ session.queueDeclare(arg::queue=control, arg::durable=true);
+ } else {
+ session.queueDeclare(arg::queue=control, arg::exclusive=true, arg::autoDelete=true);
+ }
+ session.exchangeBind(arg::exchange="amq.topic", arg::queue=control, arg::bindingKey="topic_control");
+
+ //set up listener
+ SubscriptionManager mgr(session);
+ Listener listener(session, mgr, "response", args.transactional);
+ SubscriptionSettings settings;
+ if (args.prefetch) {
+ settings.autoAck = (args.ack ? args.ack : (args.prefetch / 2));
+ settings.flowControl = FlowControl::messageCredit(args.prefetch);
+ } else {
+ settings.acceptMode = ACCEPT_MODE_NONE;
+ settings.flowControl = FlowControl::unlimited();
+ }
+ listener.subscription = mgr.subscribe(listener, control, settings);
+ session.sync();
+
+ if( args.statusqueue.length() > 0 ) {
+ stringstream msg_str;
+ msg_str << "topic_listener: " << (int)getpid();
+ session.messageTransfer(arg::content=Message(msg_str.str(), args.statusqueue));
+ cout << "Ready status put on queue '" << args.statusqueue << "'" << endl;
+ }
+
+ if (args.transactional) {
+ session.txSelect();
+ }
+
+ cout << "topic_listener: listening..." << endl;
+ mgr.run();
+ if (args.durable) {
+ session.queueDelete(arg::queue=control);
+ }
+ session.close();
+ cout << "closing connection" << endl;
+ connection.close();
+ }
+ return 0;
+ } catch (const std::exception& error) {
+ cout << "topic_listener: " << error.what() << endl;
+ }
+ return 1;
+}
+
+Listener::Listener(const Session& s, SubscriptionManager& m, const string& _responseq, bool tx) :
+ session(s), mgr(m), responseQueue(_responseq), transactional(tx), init(false), count(0){}
+
+void Listener::received(Message& message){
+ if(!init){
+ start = now();
+ count = 0;
+ init = true;
+ cout << "Batch started." << endl;
+ }
+ string type = message.getHeaders().getAsString("TYPE");
+
+ if(string("TERMINATION_REQUEST") == type){
+ shutdown();
+ }else if(string("REPORT_REQUEST") == type){
+ subscription.accept(subscription.getUnaccepted()); // Accept everything upto this point
+ cout <<"Batch ended, sending report." << endl;
+ //send a report:
+ report();
+ init = false;
+ }else if (++count % 1000 == 0){
+ cout <<"Received " << count << " messages." << endl;
+ }
+}
+
+void Listener::shutdown(){
+ mgr.stop();
+}
+
+void Listener::report(){
+ AbsTime finish = now();
+ Duration time(start, finish);
+ stringstream reportstr;
+ reportstr << "Received " << count << " messages in "
+ << time/TIME_MSEC << " ms.";
+ Message msg(reportstr.str(), responseQueue);
+ msg.getHeaders().setString("TYPE", "REPORT");
+ session.messageTransfer(arg::destination="amq.direct", arg::content=msg, arg::acceptMode=1);
+ if(transactional){
+ sync(session).txCommit();
+ }
+}
+
diff --git a/RC9/qpid/cpp/src/tests/topic_perftest b/RC9/qpid/cpp/src/tests/topic_perftest
new file mode 100755
index 0000000000..cd440b2458
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/topic_perftest
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+exec `dirname $0`/run_perftest 10000 --mode topic --qt 16
diff --git a/RC9/qpid/cpp/src/tests/topic_publisher.cpp b/RC9/qpid/cpp/src/tests/topic_publisher.cpp
new file mode 100644
index 0000000000..f37ad2dc0e
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/topic_publisher.cpp
@@ -0,0 +1,224 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/**
+ * This file provides one half of a test and example of a pub-sub
+ * style of interaction. See topic_listener.cpp for the other half, in
+ * which the logic for subscribers is defined.
+ *
+ * This file contains the publisher logic. The publisher will send a
+ * number of messages to the exchange with the appropriate routing key
+ * for the logical 'topic'. Once it has done this it will then send a
+ * request that each subscriber report back with the number of message
+ * it has received and the time that elapsed between receiving the
+ * first one and receiving the report request. Once the expected
+ * number of reports are received, it sends out a request that each
+ * subscriber shutdown.
+ */
+
+#include "TestOptions.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/MessageListener.h"
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/sys/Monitor.h"
+#include <unistd.h>
+#include "qpid/sys/Time.h"
+#include <cstdlib>
+#include <iostream>
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace qpid::sys;
+using namespace std;
+
+/**
+ * The publishing logic is defined in this class. It implements
+ * message listener and can therfore be used to receive messages sent
+ * back by the subscribers.
+ */
+class Publisher {
+ AsyncSession session;
+ SubscriptionManager mgr;
+ LocalQueue queue;
+ const string controlTopic;
+ const bool transactional;
+ const bool durable;
+
+ string generateData(int size);
+
+public:
+ Publisher(const AsyncSession& session, const string& controlTopic, bool tx, bool durable);
+ int64_t publish(int msgs, int listeners, int size);
+ void terminate();
+};
+
+/**
+ * A utility class for managing the options passed in to the test
+ */
+struct Args : public TestOptions {
+ int messages;
+ int subscribers;
+ bool transactional;
+ bool durable;
+ int batches;
+ int delay;
+ int size;
+ string statusqueue;
+
+ Args() : messages(1000), subscribers(1),
+ transactional(false), durable(false),
+ batches(1), delay(0), size(256)
+ {
+ addOptions()
+ ("messages", optValue(messages, "N"), "how many messages to send")
+ ("subscribers", optValue(subscribers, "N"), "how many subscribers to expect reports from")
+ ("transactional", optValue(transactional), "client should use transactions")
+ ("durable", optValue(durable), "messages should be durable")
+ ("batches", optValue(batches, "N"), "how many batches to run")
+ ("delay", optValue(delay, "SECONDS"), "Causes a delay between each batch")
+ ("size", optValue(size, "BYTES"), "size of the published messages")
+ ("status-queue", optValue(statusqueue, "QUEUE-NAME"), "Message queue to read status messages from");
+ }
+};
+
+int main(int argc, char** argv) {
+ try{
+ Args args;
+ args.parse(argc, argv);
+ if(args.help)
+ cout << args << endl;
+ else {
+ Connection connection;
+ args.open(connection);
+ AsyncSession session = connection.newSession();
+
+ // If status-queue is defined, wait for all expected listeners to join in before we start
+ if( args.statusqueue.length() > 0 ) {
+ cout << "Waiting for " << args.subscribers << " listeners..." << endl;
+ SubscriptionManager statusSubs(session);
+ LocalQueue statusQ;
+ statusSubs.subscribe(statusQ, args.statusqueue);
+ for (int i = 0; i < args.subscribers; i++) {
+ Message m = statusQ.get();
+ if( m.getData().find("topic_listener: ", 0) == 0 ) {
+ cout << "Listener " << (i+1) << " of " << args.subscribers
+ << " is ready (pid " << m.getData().substr(16, m.getData().length() - 16)
+ << ")" << endl;
+ } else {
+ throw Exception(QPID_MSG("Unexpected message received on status queue: " << m.getData()));
+ }
+ }
+ }
+
+ if (args.transactional) {
+ session.txSelect();
+ }
+ session.queueDeclare(arg::queue="response");
+ session.exchangeBind(arg::exchange="amq.direct", arg::queue="response", arg::bindingKey="response");
+
+ Publisher publisher(session, "topic_control", args.transactional, args.durable);
+
+ int batchSize(args.batches);
+ int64_t max(0);
+ int64_t min(0);
+ int64_t sum(0);
+ for(int i = 0; i < batchSize; i++){
+ if(i > 0 && args.delay) sleep(args.delay);
+ int64_t msecs =
+ publisher.publish(args.messages,
+ args.subscribers,
+ args.size) / TIME_MSEC;
+ if(!max || msecs > max) max = msecs;
+ if(!min || msecs < min) min = msecs;
+ sum += msecs;
+ cout << "Completed " << (i+1) << " of " << batchSize
+ << " in " << msecs << "ms" << endl;
+ }
+ publisher.terminate();
+ int64_t avg = sum / batchSize;
+ if(batchSize > 1){
+ cout << batchSize << " batches completed. avg=" << avg <<
+ ", max=" << max << ", min=" << min << endl;
+ }
+ session.close();
+ connection.close();
+ }
+ return 0;
+ }catch(exception& error) {
+ cout << error.what() << endl;
+ }
+ return 1;
+}
+
+Publisher::Publisher(const AsyncSession& _session, const string& _controlTopic, bool tx, bool d) :
+ session(_session), mgr(session), controlTopic(_controlTopic), transactional(tx), durable(d)
+{
+ mgr.subscribe(queue, "response");
+}
+
+int64_t Publisher::publish(int msgs, int listeners, int size){
+ Message msg(generateData(size), controlTopic);
+ if (durable) {
+ msg.getDeliveryProperties().setDeliveryMode(framing::PERSISTENT);
+ }
+ AbsTime start = now();
+
+ for(int i = 0; i < msgs; i++){
+ session.messageTransfer(arg::content=msg, arg::destination="amq.topic", arg::acceptMode=1);
+ }
+ //send report request
+ Message reportRequest("", controlTopic);
+ reportRequest.getHeaders().setString("TYPE", "REPORT_REQUEST");
+ session.messageTransfer(arg::content=reportRequest, arg::destination="amq.topic", arg::acceptMode=1);
+ if(transactional){
+ sync(session).txCommit();
+ }
+ //wait for a response from each listener (TODO, could log these)
+ for (int i = 0; i < listeners; i++) {
+ Message report = queue.pop();
+ }
+
+ if(transactional){
+ sync(session).txCommit();
+ }
+
+ AbsTime finish = now();
+ return Duration(start, finish);
+}
+
+string Publisher::generateData(int size){
+ string data;
+ for(int i = 0; i < size; i++){
+ data += ('A' + (i / 26));
+ }
+ return data;
+}
+
+void Publisher::terminate(){
+ //send termination request
+ Message terminationRequest("", controlTopic);
+ terminationRequest.getHeaders().setString("TYPE", "TERMINATION_REQUEST");
+ session.messageTransfer(arg::content=terminationRequest, arg::destination="amq.topic", arg::acceptMode=1);
+ if(transactional){
+ session.txCommit();
+ }
+}
diff --git a/RC9/qpid/cpp/src/tests/topictest b/RC9/qpid/cpp/src/tests/topictest
new file mode 100755
index 0000000000..8fd680ee35
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/topictest
@@ -0,0 +1,61 @@
+#!/bin/bash
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Run the C++ topic test
+
+# Clean up old log files
+rm -f subscriber_*.log
+
+# Defaults values
+SUBSCRIBERS=10
+MESSAGES=2000
+BATCHES=10
+
+while getopts "s:m:b:h:t" opt ; do
+ case $opt in
+ s) SUBSCRIBERS=$OPTARG ;;
+ m) MESSAGES=$OPTARG ;;
+ b) BATCHES=$OPTARG ;;
+ h) HOST=-h$OPTARG ;;
+ t) TRANSACTIONAL="--transactional --durable" ;;
+ ?)
+ echo "Usage: %0 [-s <subscribers>] [-m <messages.] [-b <batches>]"
+ exit 1
+ ;;
+ esac
+done
+
+subscribe() {
+ echo Start subscriber $1
+ LOG="subscriber_$1.log"
+ ./topic_listener $TRANSACTIONAL > $LOG 2>&1 && rm -f $LOG
+}
+
+publish() {
+ ./topic_publisher --messages $MESSAGES --batches $BATCHES --subscribers $SUBSCRIBERS $HOST $TRANSACTIONAL
+}
+
+for ((i=$SUBSCRIBERS ; i--; )); do
+ subscribe $i &
+done
+# FIXME aconway 2007-03-27: Hack around startup race. Fix topic test.
+sleep 2
+publish 2>&1 || exit 1
diff --git a/RC9/qpid/cpp/src/tests/txjob.cpp b/RC9/qpid/cpp/src/tests/txjob.cpp
new file mode 100644
index 0000000000..94db96a666
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/txjob.cpp
@@ -0,0 +1,95 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <iostream>
+#include <boost/bind.hpp>
+#include <boost/ptr_container/ptr_vector.hpp>
+
+#include "TestOptions.h"
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/FailoverManager.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/sys/Thread.h"
+
+using namespace qpid::client;
+using namespace qpid::sys;
+
+struct Args : public qpid::TestOptions
+{
+ string workQueue;
+ string source;
+ string dest;
+ uint messages;
+ uint jobs;
+ bool quit;
+ bool declareQueues;
+
+ Args() : workQueue("txshift-control"), source("txshift-1"), dest("txshift-2"), messages(0), jobs(0),
+ quit(false), declareQueues(false)
+ {
+ addOptions()
+ ("messages", qpid::optValue(messages, "N"), "Number of messages to shift")
+ ("jobs", qpid::optValue(jobs, "N"), "Number of shift jobs to request")
+ ("source", qpid::optValue(source, "QUEUE NAME"), "source queue from which messages will be shifted")
+ ("dest", qpid::optValue(dest, "QUEUE NAME"), "dest queue to which messages will be shifted")
+ ("work-queue", qpid::optValue(workQueue, "QUEUE NAME"), "work queue from which to take instructions")
+ ("add-quit", qpid::optValue(quit), "add a 'quit' instruction to the queue (after any other jobs)")
+ ("declare-queues", qpid::optValue(declareQueues), "issue a declare for all queues");
+ }
+};
+
+//TODO: might be nice to make this capable of failover as well at some
+//point; for now its just for the setup phase.
+int main(int argc, char** argv)
+{
+ Args opts;
+ try {
+ opts.parse(argc, argv);
+ Connection connection;
+ connection.open(opts.con);
+ Session session = connection.newSession();
+ if (opts.declareQueues) {
+ session.queueDeclare(arg::queue=opts.workQueue);
+ session.queueDeclare(arg::queue=opts.source);
+ session.queueDeclare(arg::queue=opts.dest);
+ }
+ for (uint i = 0; i < opts.jobs; ++i) {
+ Message job("transfer", opts.workQueue);
+ job.getHeaders().setString("src", opts.source);
+ job.getHeaders().setString("dest", opts.dest);
+ job.getHeaders().setInt("count", opts.messages);
+ async(session).messageTransfer(arg::content=job);
+ }
+
+ if (opts.quit) {
+ async(session).messageTransfer(arg::content=Message("quit", opts.workQueue));
+ }
+
+ session.sync();
+ session.close();
+
+ return 0;
+ } catch(const std::exception& e) {
+ std::cout << e.what() << std::endl;
+ return 1;
+ }
+}
diff --git a/RC9/qpid/cpp/src/tests/txshift.cpp b/RC9/qpid/cpp/src/tests/txshift.cpp
new file mode 100644
index 0000000000..5db08d7a53
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/txshift.cpp
@@ -0,0 +1,185 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <iostream>
+#include <boost/bind.hpp>
+#include <boost/ptr_container/ptr_vector.hpp>
+
+#include "TestOptions.h"
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/FailoverManager.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/log/Statement.h"
+#include "qpid/sys/Thread.h"
+
+using namespace qpid::client;
+using namespace qpid::sys;
+
+struct Args : public qpid::TestOptions
+{
+ string workQueue;
+ size_t workers;
+
+ Args() : workQueue("txshift-control"), workers(1)
+ {
+ addOptions()
+ ("workers", qpid::optValue(workers, "N"), "Number of separate worker sessions to start")
+ ("work-queue", qpid::optValue(workQueue, "NAME"), "work queue from which to take instructions");
+ }
+};
+
+struct Transfer : MessageListener
+{
+ std::string control;
+ std::string source;
+ std::string destination;
+ uint expected;
+ uint transfered;
+ SubscriptionSettings controlSettings;
+ Subscription controlSubscription;
+ SubscriptionSettings sourceSettings;
+ Subscription sourceSubscription;
+
+ Transfer(const std::string control_) : control(control_), expected(0), transfered(0) {}
+
+ void subscribeToSource(SubscriptionManager& manager)
+ {
+ sourceSettings.autoAck = 0;//will accept once at the end of the batch
+ sourceSettings.flowControl = FlowControl::messageCredit(expected);
+ sourceSubscription = manager.subscribe(*this, source, sourceSettings);
+ QPID_LOG(info, "Subscribed to source: " << source << " expecting: " << expected);
+ }
+
+ void subscribeToControl(SubscriptionManager& manager)
+ {
+ controlSettings.flowControl = FlowControl::messageCredit(1);
+ controlSubscription = manager.subscribe(*this, control, controlSettings);
+ QPID_LOG(info, "Subscribed to job queue");
+ }
+
+ void received(Message& message)
+ {
+ QPID_LOG(debug, "received: " << message.getData() << " for " << message.getDestination());
+ if (message.getDestination() == source) {
+ receivedFromSource(message);
+ } else if (message.getDestination() == control) {
+ receivedFromControl(message);
+ } else {
+ QPID_LOG(error, "Unexpected message: " << message.getData() << " to " << message.getDestination());
+ }
+ }
+
+ void receivedFromSource(Message& message)
+ {
+ QPID_LOG(debug, "transfering " << (transfered+1) << " of " << expected);
+ message.getDeliveryProperties().setRoutingKey(destination);
+ async(sourceSubscription.getSession()).messageTransfer(arg::content=message);
+ if (++transfered == expected) {
+ QPID_LOG(info, "completed job: " << transfered << " messages shifted from " <<
+ source << " to " << destination);
+ sourceSubscription.accept(sourceSubscription.getUnaccepted());
+ sourceSubscription.getSession().txCommit();
+ sourceSubscription.cancel();
+ //grant credit to allow broker to send us another control message
+ controlSubscription.grantMessageCredit(1);
+ }
+ }
+
+ void receivedFromControl(Message& message)
+ {
+ if (message.getData() == "transfer") {
+ source = message.getHeaders().getAsString("src");
+ destination = message.getHeaders().getAsString("dest");
+ expected = message.getHeaders().getAsInt("count");
+ transfered = 0;
+ QPID_LOG(info, "received transfer request: " << expected << " messages to be shifted from " <<
+ source << " to " << destination);
+ subscribeToSource(controlSubscription.getSubscriptionManager());
+ } else if (message.getData() == "quit") {
+ QPID_LOG(info, "received quit request");
+ controlSubscription.cancel();
+ } else {
+ std::cerr << "Rejecting invalid message: " << message.getData() << std::endl;
+ controlSubscription.getSession().messageReject(SequenceSet(message.getId()));
+ }
+ }
+
+};
+
+struct Worker : FailoverManager::Command, Runnable
+{
+ FailoverManager& connection;
+ Transfer transfer;
+ Thread runner;
+
+ Worker(FailoverManager& c, const std::string& controlQueue) : connection(c), transfer(controlQueue) {}
+
+ void run()
+ {
+ connection.execute(*this);
+ }
+
+ void start()
+ {
+ runner = Thread(this);
+ }
+
+ void join()
+ {
+ runner.join();
+ }
+
+ void execute(AsyncSession& session, bool isRetry)
+ {
+ if (isRetry) QPID_LOG(info, "Retrying...");
+ session.txSelect();
+ SubscriptionManager subs(session);
+ transfer.subscribeToControl(subs);
+ subs.run();
+ }
+};
+
+int main(int argc, char** argv)
+{
+ Args opts;
+ try {
+ opts.parse(argc, argv);
+ FailoverManager connection(opts.con);
+ connection.connect();
+ if (opts.workers == 1) {
+ Worker worker(connection, opts.workQueue);
+ worker.run();
+ } else {
+ boost::ptr_vector<Worker> workers;
+ for (size_t i = 0; i < opts.workers; i++) {
+ workers.push_back(new Worker(connection, opts.workQueue));
+ }
+ for_each(workers.begin(), workers.end(), boost::bind(&Worker::start, _1));
+ for_each(workers.begin(), workers.end(), boost::bind(&Worker::join, _1));
+ }
+
+ return 0;
+ } catch(const std::exception& e) {
+ std::cout << e.what() << std::endl;
+ return 1;
+ }
+}
diff --git a/RC9/qpid/cpp/src/tests/txtest.cpp b/RC9/qpid/cpp/src/tests/txtest.cpp
new file mode 100644
index 0000000000..0c8ce90648
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/txtest.cpp
@@ -0,0 +1,329 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <algorithm>
+#include <iomanip>
+#include <iostream>
+#include <memory>
+#include <sstream>
+#include <vector>
+
+#include "TestOptions.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/framing/Array.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/sys/uuid.h"
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace qpid::sys;
+using std::string;
+
+typedef std::vector<std::string> StringSet;
+
+struct Args : public qpid::TestOptions {
+ bool init, transfer, check;//actions
+ uint size;
+ bool durable;
+ uint queues;
+ string base;
+ uint msgsPerTx;
+ uint txCount;
+ uint totalMsgCount;
+ bool dtx;
+ bool quiet;
+
+ Args() : init(true), transfer(true), check(true),
+ size(256), durable(true), queues(2),
+ base("tx-test"), msgsPerTx(1), txCount(1), totalMsgCount(10),
+ dtx(false), quiet(false)
+ {
+ addOptions()
+
+ ("init", optValue(init, "yes|no"), "Declare queues and populate one with the initial set of messages.")
+ ("transfer", optValue(transfer, "yes|no"), "'Move' messages from one queue to another using transactions to ensure no message loss.")
+ ("check", optValue(check, "yes|no"), "Check that the initial messages are all still available.")
+ ("size", optValue(size, "N"), "message size")
+ ("durable", optValue(durable, "yes|no"), "use durable messages")
+ ("queues", optValue(queues, "N"), "number of queues")
+ ("queue-base-name", optValue(base, "<name>"), "base name for queues")
+ ("messages-per-tx", optValue(msgsPerTx, "N"), "number of messages transferred per transaction")
+ ("tx-count", optValue(txCount, "N"), "number of transactions per 'agent'")
+ ("total-messages", optValue(totalMsgCount, "N"), "total number of messages in 'circulation'")
+ ("dtx", optValue(dtx, "yes|no"), "use distributed transactions")
+ ("quiet", optValue(quiet), "reduce output from test");
+ }
+};
+
+const std::string chars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
+
+std::string generateData(uint size)
+{
+ if (size < chars.length()) {
+ return chars.substr(0, size);
+ }
+ std::string data;
+ for (uint i = 0; i < (size / chars.length()); i++) {
+ data += chars;
+ }
+ data += chars.substr(0, size % chars.length());
+ return data;
+}
+
+void generateSet(const std::string& base, uint count, StringSet& collection)
+{
+ for (uint i = 0; i < count; i++) {
+ std::ostringstream out;
+ out << base << "-" << (i+1);
+ collection.push_back(out.str());
+ }
+}
+
+Args opts;
+
+struct Client
+{
+ Connection connection;
+ AsyncSession session;
+
+ Client()
+ {
+ opts.open(connection);
+ session = connection.newSession();
+ }
+
+ ~Client()
+ {
+ try{
+ session.close();
+ connection.close();
+ } catch(const std::exception& e) {
+ std::cout << e.what() << std::endl;
+ }
+ }
+};
+
+struct Transfer : public Client, public Runnable
+{
+ std::string src;
+ std::string dest;
+ Thread thread;
+ uuid_t uuid;
+ char uuidStr[37]; // Format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + trailing \0
+ framing::Xid xid;
+
+ Transfer(const std::string& to, const std::string& from) : src(to), dest(from), xid(0x4c414e47, "", from) {}
+
+ void run()
+ {
+ try {
+
+ if (opts.dtx) session.dtxSelect();
+ else session.txSelect();
+ SubscriptionManager subs(session);
+
+ LocalQueue lq;
+ SubscriptionSettings settings(FlowControl::messageWindow(opts.msgsPerTx));
+ settings.autoAck = 0; // Disabled
+ Subscription sub = subs.subscribe(lq, src, settings);
+
+ for (uint t = 0; t < opts.txCount; t++) {
+ Message in;
+ Message out("", dest);
+ if (opts.dtx) {
+ setNewXid(xid);
+ session.dtxStart(arg::xid=xid);
+ }
+ for (uint m = 0; m < opts.msgsPerTx; m++) {
+ in = lq.pop();
+ out.setData(in.getData());
+ out.getMessageProperties().setCorrelationId(in.getMessageProperties().getCorrelationId());
+ out.getDeliveryProperties().setDeliveryMode(in.getDeliveryProperties().getDeliveryMode());
+ session.messageTransfer(arg::content=out, arg::acceptMode=1);
+ }
+ sub.accept(sub.getUnaccepted());
+ if (opts.dtx) {
+ session.dtxEnd(arg::xid=xid);
+ session.dtxPrepare(arg::xid=xid);
+ session.dtxCommit(arg::xid=xid);
+ } else {
+ session.txCommit();
+ }
+ }
+ } catch(const std::exception& e) {
+ std::cout << "Transfer interrupted: " << e.what() << std::endl;
+ }
+ }
+
+ void setNewXid(framing::Xid& xid) {
+ ::uuid_generate(uuid);
+ ::uuid_unparse(uuid, uuidStr);
+ xid.setGlobalId(uuidStr);
+ }
+};
+
+struct Controller : public Client
+{
+ StringSet ids;
+ StringSet queues;
+
+ Controller()
+ {
+ generateSet(opts.base, opts.queues, queues);
+ generateSet("msg", opts.totalMsgCount, ids);
+ }
+
+ void init()
+ {
+ //declare queues
+ for (StringSet::iterator i = queues.begin(); i != queues.end(); i++) {
+ session.queueDeclare(arg::queue=*i, arg::durable=opts.durable);
+ session.sync();
+ }
+
+ Message msg(generateData(opts.size), *queues.begin());
+ if (opts.durable) {
+ msg.getDeliveryProperties().setDeliveryMode(framing::PERSISTENT);
+ }
+
+ //publish messages
+ for (StringSet::iterator i = ids.begin(); i != ids.end(); i++) {
+ msg.getMessageProperties().setCorrelationId(*i);
+ session.messageTransfer(arg::content=msg, arg::acceptMode=1);
+ }
+ }
+
+ void transfer()
+ {
+ boost::ptr_vector<Transfer> agents(opts.queues);
+ //launch transfer agents
+ for (StringSet::iterator i = queues.begin(); i != queues.end(); i++) {
+ StringSet::iterator next = i + 1;
+ if (next == queues.end()) next = queues.begin();
+
+ if (!opts.quiet) std::cout << "Transfering from " << *i << " to " << *next << std::endl;
+ agents.push_back(new Transfer(*i, *next));
+ agents.back().thread = Thread(agents.back());
+ }
+
+ for (boost::ptr_vector<Transfer>::iterator i = agents.begin(); i != agents.end(); i++) {
+ i->thread.join();
+ }
+ }
+
+ int check()
+ {
+ SubscriptionManager subs(session);
+
+ // Recover DTX transactions (if any)
+ if (opts.dtx) {
+ std::vector<std::string> inDoubtXids;
+ framing::DtxRecoverResult dtxRes = session.dtxRecover().get();
+ const framing::Array& xidArr = dtxRes.getInDoubt();
+ xidArr.collect(inDoubtXids);
+
+ if (inDoubtXids.size()) {
+ if (!opts.quiet) std::cout << "Recovering DTX in-doubt transaction(s):" << std::endl;
+ framing::StructHelper decoder;
+ framing::Xid xid;
+ // abort even, commit odd transactions
+ for (unsigned i = 0; i < inDoubtXids.size(); i++) {
+ decoder.decode(xid, inDoubtXids[i]);
+ if (!opts.quiet) std::cout << (i%2 ? " * aborting " : " * committing ");
+ xid.print(std::cout);
+ std::cout << std::endl;
+ if (i%2) {
+ session.dtxRollback(arg::xid=xid);
+ } else {
+ session.dtxCommit(arg::xid=xid);
+ }
+ }
+ }
+ }
+
+ StringSet drained;
+ //drain each queue and verify the correct set of messages are available
+ for (StringSet::iterator i = queues.begin(); i != queues.end(); i++) {
+ //subscribe, allocate credit and flushn
+ LocalQueue lq;
+ SubscriptionSettings settings(FlowControl::unlimited(), ACCEPT_MODE_NONE);
+ subs.subscribe(lq, *i, settings);
+ session.messageFlush(arg::destination=*i);
+ session.sync();
+
+ uint count(0);
+ while (!lq.empty()) {
+ Message m = lq.pop();
+ //add correlation ids of received messages to drained
+ drained.push_back(m.getMessageProperties().getCorrelationId());
+ ++count;
+ }
+ if (!opts.quiet) std::cout << "Drained " << count << " messages from " << *i << std::endl;
+ }
+
+ sort(ids.begin(), ids.end());
+ sort(drained.begin(), drained.end());
+
+ //check that drained == ids
+ StringSet missing;
+ set_difference(ids.begin(), ids.end(), drained.begin(), drained.end(), back_inserter(missing));
+
+ StringSet extra;
+ set_difference(drained.begin(), drained.end(), ids.begin(), ids.end(), back_inserter(extra));
+
+ if (missing.empty() && extra.empty()) {
+ std::cout << "All expected messages were retrieved." << std::endl;
+ return 0;
+ } else {
+ if (!missing.empty()) {
+ std::cout << "The following ids were missing:" << std::endl;
+ for (StringSet::iterator i = missing.begin(); i != missing.end(); i++) {
+ std::cout << " '" << *i << "'" << std::endl;
+ }
+ }
+ if (!extra.empty()) {
+ std::cout << "The following extra ids were encountered:" << std::endl;
+ for (StringSet::iterator i = extra.begin(); i != extra.end(); i++) {
+ std::cout << " '" << *i << "'" << std::endl;
+ }
+ }
+ return 1;
+ }
+ }
+};
+
+int main(int argc, char** argv)
+{
+ try {
+ opts.parse(argc, argv);
+ Controller controller;
+ if (opts.init) controller.init();
+ if (opts.transfer) controller.transfer();
+ if (opts.check) return controller.check();
+ return 0;
+ } catch(const std::exception& e) {
+ std::cout << e.what() << std::endl;
+ }
+ return 2;
+}
diff --git a/RC9/qpid/cpp/src/tests/unit_test.cpp b/RC9/qpid/cpp/src/tests/unit_test.cpp
new file mode 100644
index 0000000000..00c61242e4
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/unit_test.cpp
@@ -0,0 +1,23 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// Defines test_main function to link with actual unit test code.
+#define BOOST_AUTO_TEST_MAIN // Boost 1.33
+#define BOOST_TEST_MAIN
+#include "unit_test.h"
+
diff --git a/RC9/qpid/cpp/src/tests/unit_test.h b/RC9/qpid/cpp/src/tests/unit_test.h
new file mode 100644
index 0000000000..df3ebfb1fe
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/unit_test.h
@@ -0,0 +1,86 @@
+#ifndef QPIPD_TEST_UNIT_TEST_H_
+#define QPIPD_TEST_UNIT_TEST_H_
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+// Workaround so we can build against boost 1.33 and boost 1.34.
+// Remove when we no longer need to support 1.33.
+//
+#include <boost/version.hpp>
+#include <limits.h> // Must be inclued beofre boost/test headers.
+
+// #include the correct header file.
+//
+#if (BOOST_VERSION < 103400)
+# include <boost/test/auto_unit_test.hpp>
+#else
+# include <boost/test/unit_test.hpp>
+#endif // BOOST_VERSION
+
+// Workarounds for BOOST_AUTO_TEST_CASE|SUITE|SUITE_END
+//
+#if (BOOST_VERSION < 103300)
+
+# define QPID_AUTO_TEST_SUITE(name)
+# define QPID_AUTO_TEST_CASE(name) BOOST_AUTO_UNIT_TEST(name)
+# define QPID_AUTO_TEST_SUITE_END()
+
+#elif (BOOST_VERSION < 103400)
+// Note the trailing ';'
+# define QPID_AUTO_TEST_SUITE(name) BOOST_AUTO_TEST_SUITE(name);
+# define QPID_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END();
+
+#endif // Workarounds for BOOST_AUTO_TEST_CASE|SUITE|SUITE_END
+
+// Workaround for BOOST_AUTO_TEST_SUITE_EXPECTED_FAILURES
+//
+#if (BOOST_VERSION < 103600)
+
+// Keep the test function for compilation but do not not register it.
+// TODO aconway 2008-04-23: better workaround for expected failures.
+# define QPID_AUTO_TEST_CASE_EXPECTED_FAILURES(test_name,n) \
+ namespace { struct test_name { void test_method(); }; } \
+ void test_name::test_method()
+
+#endif // Workaround for BOOST_AUTO_TEST_SUITE_EXPECTED_FAILURES
+
+//
+// Default definitions for latest version of boost.
+//
+
+#ifndef QPID_AUTO_TEST_SUITE
+# define QPID_AUTO_TEST_SUITE(name) BOOST_AUTO_TEST_SUITE(name)
+#endif
+
+#ifndef QPID_AUTO_TEST_CASE
+# define QPID_AUTO_TEST_CASE(name) BOOST_AUTO_TEST_CASE(name)
+#endif
+
+#ifndef QPID_AUTO_TEST_CASE_EXPECTED_FAILURES
+# define QPID_AUTO_TEST_CASE_EXPECTED_FAILURES(name,n) BOOST_AUTO_TEST_CASE_EXPECTED_FAILURES(name,n)
+#endif
+
+#ifndef QPID_AUTO_TEST_SUITE_END
+# define QPID_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
+#endif
+
+#endif // !QPIPD_TEST_UNIT_TEST_H_
diff --git a/RC9/qpid/cpp/src/tests/vg_check b/RC9/qpid/cpp/src/tests/vg_check
new file mode 100644
index 0000000000..c5a1e6d2d0
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/vg_check
@@ -0,0 +1,24 @@
+# Check for valgrind errors. Sourced by test scripts.
+
+vg_failed() {
+ echo "Valgrind error log in $VG_LOG." 1>&2
+ cat $VG_LOG 1>&2
+ echo $1 1>&2
+ exit 1
+}
+
+vg_check()
+{
+ test -z "$1" || VG_LOG=$1
+ test -f $VG_LOG || vg_failed Valgrind log file $VG_LOG missing.
+ # Ensure there is an ERROR SUMMARY line.
+ grep -E '^==[0-9]+== ERROR SUMMARY:' $VG_LOG > /dev/null || \
+ vg_failed "No valgrind ERROR SUMMARY line in $VG_LOG."
+ # Ensure that the number of errors is 0.
+ grep -E '^==[0-9]+== ERROR SUMMARY: [^0]' $VG_LOG > /dev/null && \
+ vg_failed "Valgrind reported errors in $VG_LOG; see above."
+ # Check for leaks.
+ grep -E '^==[0-9]+== +.* lost: [^0]' $VG_LOG && \
+ vg_failed "Found memory leaks (see log file, $VG_LOG); see above."
+ true
+}
diff --git a/RC9/qpid/cpp/src/windows/QpiddBroker.cpp b/RC9/qpid/cpp/src/windows/QpiddBroker.cpp
new file mode 100644
index 0000000000..6714ac2e01
--- /dev/null
+++ b/RC9/qpid/cpp/src/windows/QpiddBroker.cpp
@@ -0,0 +1,89 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpidd.h"
+#include "qpid/Exception.h"
+#include "qpid/Options.h"
+#include "qpid/Plugin.h"
+#include "qpid/sys/IntegerTypes.h"
+#include "qpid/sys/windows/check.h"
+#include "qpid/broker/Broker.h"
+
+#include <iostream>
+
+// These need to be made something sensible, like reading a value from
+// the registry. But for now, get things going with a local definition.
+namespace {
+const char *CONF_FILE = "qpid_broker.conf";
+const char *MODULE_DIR = ".";
+}
+
+using namespace qpid::broker;
+
+BootstrapOptions::BootstrapOptions(const char* argv0)
+ : qpid::Options("Options"),
+ common("", CONF_FILE),
+ module(MODULE_DIR),
+ log(argv0)
+{
+ add(common);
+ add(module);
+ add(log);
+}
+
+struct QpiddWindowsOptions : public QpiddOptionsPrivate {
+ QpiddWindowsOptions(QpiddOptions *parent) : QpiddOptionsPrivate(parent) {
+ }
+};
+
+QpiddOptions::QpiddOptions(const char* argv0)
+ : qpid::Options("Options"),
+ common("", CONF_FILE),
+ module(MODULE_DIR),
+ log(argv0)
+{
+ add(common);
+ add(module);
+ add(broker);
+ add(log);
+
+ platform.reset(new QpiddWindowsOptions(this));
+ qpid::Plugin::addOptions(*this);
+}
+
+void QpiddOptions::usage() const {
+ std::cout << "Usage: qpidd [OPTIONS]" << std::endl << std::endl
+ << *this << std::endl;
+}
+
+int QpiddBroker::execute (QpiddOptions *options) {
+ // Options that affect a running daemon.
+ QpiddWindowsOptions *myOptions =
+ reinterpret_cast<QpiddWindowsOptions *>(options->platform.get());
+ if (myOptions == 0)
+ throw qpid::Exception("Internal error obtaining platform options");
+
+ boost::intrusive_ptr<Broker> brokerPtr(new Broker(options->broker));
+ if (options->broker.port == 0)
+ std::cout << (uint16_t)(brokerPtr->getPort("")) << std::endl;
+ brokerPtr->run();
+ return 0;
+}
diff --git a/RC9/qpid/cpp/src/xml.mk b/RC9/qpid/cpp/src/xml.mk
new file mode 100644
index 0000000000..957a18efde
--- /dev/null
+++ b/RC9/qpid/cpp/src/xml.mk
@@ -0,0 +1,28 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+dmodule_LTLIBRARIES += xml.la
+
+xml_la_SOURCES = \
+ qpid/xml/XmlExchange.cpp \
+ qpid/xml/XmlExchange.h \
+ qpid/xml/XmlExchangePlugin.cpp
+
+xml_la_LIBADD = -lxerces-c -lxqilla libqpidbroker.la
+
+xml_la_LDFLAGS = $(PLUGINLDFLAGS)