summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAidan Skinner <aidan@apache.org>2008-04-14 10:44:28 +0000
committerAidan Skinner <aidan@apache.org>2008-04-14 10:44:28 +0000
commit5c1648acbc1742c0e19603dca5574e6b3c71f0d7 (patch)
treedb32badcb18d406d137970c3fecaa68390f0db61
parent2d34e47e824a0871b328acc8ee32dfd95ae35053 (diff)
downloadqpid-python-5c1648acbc1742c0e19603dca5574e6b3c71f0d7.tar.gz
QPID-832 sync cpp with trunk
git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/branches/thegreatmerge@647727 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--qpid/cpp/DESIGN79
-rw-r--r--qpid/cpp/LICENSE203
-rw-r--r--qpid/cpp/Makefile.am43
-rw-r--r--qpid/cpp/NOTICE25
-rw-r--r--qpid/cpp/README291
-rw-r--r--qpid/cpp/RELEASE_NOTES41
-rwxr-xr-xqpid/cpp/bootstrap32
-rwxr-xr-xqpid/cpp/build-aux/compile142
-rwxr-xr-xqpid/cpp/build-aux/config.guess1501
-rwxr-xr-xqpid/cpp/build-aux/config.rpath614
-rwxr-xr-xqpid/cpp/build-aux/config.sub1619
-rwxr-xr-xqpid/cpp/build-aux/depcomp584
-rwxr-xr-xqpid/cpp/build-aux/install-sh507
-rwxr-xr-xqpid/cpp/build-aux/ltmain.sh6871
-rwxr-xr-xqpid/cpp/build-aux/mdate-sh201
-rwxr-xr-xqpid/cpp/build-aux/missing367
-rw-r--r--qpid/cpp/configure.ac212
-rw-r--r--qpid/cpp/docs/api/Makefile.am18
-rw-r--r--qpid/cpp/docs/api/developer.doxygen.in1241
-rw-r--r--qpid/cpp/docs/api/user.doxygen.in1218
-rw-r--r--qpid/cpp/docs/man/Makefile.am20
-rw-r--r--qpid/cpp/docs/man/qpidd.x46
-rwxr-xr-xqpid/cpp/etc/qpidd85
-rw-r--r--qpid/cpp/etc/qpidd.conf2
-rw-r--r--qpid/cpp/examples/Makefile.am79
-rw-r--r--qpid/cpp/examples/examples/Makefile6
-rw-r--r--qpid/cpp/examples/examples/direct/Makefile10
-rw-r--r--qpid/cpp/examples/examples/direct/declare_queues.cpp86
-rw-r--r--qpid/cpp/examples/examples/direct/direct_producer.cpp106
-rw-r--r--qpid/cpp/examples/examples/direct/listener.cpp90
-rw-r--r--qpid/cpp/examples/examples/direct/verify3
-rw-r--r--qpid/cpp/examples/examples/direct/verify.in15
-rw-r--r--qpid/cpp/examples/examples/direct/verify_cpp_python4
-rw-r--r--qpid/cpp/examples/examples/direct/verify_cpp_python.in14
-rw-r--r--qpid/cpp/examples/examples/direct/verify_python_cpp5
-rw-r--r--qpid/cpp/examples/examples/direct/verify_python_cpp.in15
-rw-r--r--qpid/cpp/examples/examples/fanout/Makefile10
-rw-r--r--qpid/cpp/examples/examples/fanout/fanout_producer.cpp104
-rw-r--r--qpid/cpp/examples/examples/fanout/listener.cpp105
-rw-r--r--qpid/cpp/examples/examples/fanout/verify6
-rw-r--r--qpid/cpp/examples/examples/fanout/verify.in43
-rw-r--r--qpid/cpp/examples/examples/fanout/verify_cpp_python7
-rw-r--r--qpid/cpp/examples/examples/fanout/verify_cpp_python.in31
-rw-r--r--qpid/cpp/examples/examples/fanout/verify_python_cpp7
-rw-r--r--qpid/cpp/examples/examples/fanout/verify_python_cpp.in29
-rw-r--r--qpid/cpp/examples/examples/pub-sub/Makefile10
-rw-r--r--qpid/cpp/examples/examples/pub-sub/topic_listener.cpp175
-rw-r--r--qpid/cpp/examples/examples/pub-sub/topic_publisher.cpp125
-rw-r--r--qpid/cpp/examples/examples/pub-sub/verify4
-rw-r--r--qpid/cpp/examples/examples/pub-sub/verify.in59
-rw-r--r--qpid/cpp/examples/examples/pub-sub/verify_cpp_python6
-rw-r--r--qpid/cpp/examples/examples/pub-sub/verify_cpp_python.in51
-rw-r--r--qpid/cpp/examples/examples/pub-sub/verify_python_cpp6
-rw-r--r--qpid/cpp/examples/examples/pub-sub/verify_python_cpp.in59
-rw-r--r--qpid/cpp/examples/examples/request-response/Makefile10
-rw-r--r--qpid/cpp/examples/examples/request-response/client.cpp179
-rw-r--r--qpid/cpp/examples/examples/request-response/server.cpp165
-rw-r--r--qpid/cpp/examples/examples/request-response/verify5
-rw-r--r--qpid/cpp/examples/examples/request-response/verify.in19
-rw-r--r--qpid/cpp/examples/examples/request-response/verify_cpp_python5
-rw-r--r--qpid/cpp/examples/examples/request-response/verify_cpp_python.in15
-rw-r--r--qpid/cpp/examples/examples/request-response/verify_python_cpp5
-rw-r--r--qpid/cpp/examples/examples/request-response/verify_python_cpp.in18
-rwxr-xr-xqpid/cpp/examples/verify85
-rwxr-xr-xqpid/cpp/examples/verify_all23
-rw-r--r--qpid/cpp/m4/clock_time.m430
-rw-r--r--qpid/cpp/m4/compiler-flags.m423
-rw-r--r--qpid/cpp/m4/cppunit.m489
-rw-r--r--qpid/cpp/m4/extensions.m458
-rwxr-xr-xqpid/cpp/make-dist83
-rwxr-xr-xqpid/cpp/managementgen/generate.py269
-rwxr-xr-xqpid/cpp/managementgen/main.py58
-rwxr-xr-xqpid/cpp/managementgen/schema.py911
-rw-r--r--qpid/cpp/managementgen/templates/Args.h40
-rw-r--r--qpid/cpp/managementgen/templates/Class.cpp117
-rw-r--r--qpid/cpp/managementgen/templates/Class.h76
-rw-r--r--qpid/cpp/managementgen/templates/Makefile.mk37
-rw-r--r--qpid/cpp/managementgen/templates/Package.cpp32
-rw-r--r--qpid/cpp/managementgen/templates/Package.h41
-rwxr-xr-xqpid/cpp/qpid-autotools-install205
-rwxr-xr-xqpid/cpp/qpid-config.in98
-rw-r--r--qpid/cpp/qpidc.spec.in253
-rw-r--r--qpid/cpp/rpm/README.qpidd-devel7
-rwxr-xr-xqpid/cpp/rubygen/0-10/allsegmenttypes.rb34
-rwxr-xr-xqpid/cpp/rubygen/0-10/exceptions.rb55
-rwxr-xr-xqpid/cpp/rubygen/0-10/handlers.rb29
-rwxr-xr-xqpid/cpp/rubygen/0-10/specification.rb334
-rwxr-xr-xqpid/cpp/rubygen/0-10/typecode.rb99
-rwxr-xr-xqpid/cpp/rubygen/99-0/MethodBodyConstVisitor.rb27
-rwxr-xr-xqpid/cpp/rubygen/99-0/MethodBodyDefaultVisitor.rb35
-rwxr-xr-xqpid/cpp/rubygen/99-0/MethodHolder.rb100
-rwxr-xr-xqpid/cpp/rubygen/99-0/Operations.rb96
-rwxr-xr-xqpid/cpp/rubygen/99-0/OperationsInvoker.rb92
-rwxr-xr-xqpid/cpp/rubygen/99-0/Proxy.rb84
-rw-r--r--qpid/cpp/rubygen/99-0/Session.rb195
-rwxr-xr-xqpid/cpp/rubygen/99-0/all_method_bodies.rb21
-rwxr-xr-xqpid/cpp/rubygen/99-0/constants.rb82
-rw-r--r--qpid/cpp/rubygen/99-0/frame_body_lists.rb31
-rw-r--r--qpid/cpp/rubygen/99-0/structs.rb590
-rwxr-xr-xqpid/cpp/rubygen/MethodBodyDefaultVisitor.rb34
-rw-r--r--qpid/cpp/rubygen/README17
-rwxr-xr-xqpid/cpp/rubygen/amqpgen.rb501
-rwxr-xr-xqpid/cpp/rubygen/cppgen.rb390
-rwxr-xr-xqpid/cpp/rubygen/generate103
-rw-r--r--qpid/cpp/src/Makefile.am502
-rw-r--r--qpid/cpp/src/cluster.mk24
-rwxr-xr-xqpid/cpp/src/generate.sh48
-rwxr-xr-xqpid/cpp/src/prof18
-rw-r--r--qpid/cpp/src/qpid/DataDir.cpp79
-rw-r--r--qpid/cpp/src/qpid/DataDir.h47
-rw-r--r--qpid/cpp/src/qpid/Exception.cpp55
-rw-r--r--qpid/cpp/src/qpid/Exception.h86
-rw-r--r--qpid/cpp/src/qpid/IList.h196
-rw-r--r--qpid/cpp/src/qpid/ISList.h176
-rw-r--r--qpid/cpp/src/qpid/InlineAllocator.h69
-rw-r--r--qpid/cpp/src/qpid/InlineVector.h68
-rw-r--r--qpid/cpp/src/qpid/Msg.h61
-rw-r--r--qpid/cpp/src/qpid/Options.cpp160
-rw-r--r--qpid/cpp/src/qpid/Options.h150
-rw-r--r--qpid/cpp/src/qpid/Plugin.cpp40
-rw-r--r--qpid/cpp/src/qpid/Plugin.h98
-rw-r--r--qpid/cpp/src/qpid/RefCounted.h78
-rw-r--r--qpid/cpp/src/qpid/Serializer.h197
-rw-r--r--qpid/cpp/src/qpid/SharedObject.h55
-rw-r--r--qpid/cpp/src/qpid/Url.cpp176
-rw-r--r--qpid/cpp/src/qpid/Url.h109
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/Array.cpp34
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/Array.h120
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/Body.h55
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/Codec.h213
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/Connection.cpp99
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/Connection.h62
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/Decimal.h51
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/Exception.h186
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/Frame.cpp28
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/FrameHeader.cpp50
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/FrameHeader.h90
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/Header.h42
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/Holder.h95
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/Map.cpp64
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/Map.h184
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/Packer.h165
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/SerializableString.h62
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/Unit.cpp64
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/Unit.h82
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/UnitHandler.h35
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/UnknownType.cpp56
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/UnknownType.h87
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/all_built_in_types.h31
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/apply.h86
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/built_in_types.h165
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/complex_types.cpp73
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/complex_types.h113
-rw-r--r--qpid/cpp/src/qpid/assert.cpp45
-rw-r--r--qpid/cpp/src/qpid/assert.h38
-rw-r--r--qpid/cpp/src/qpid/broker/Bridge.cpp96
-rw-r--r--qpid/cpp/src/qpid/broker/Bridge.h64
-rw-r--r--qpid/cpp/src/qpid/broker/Broker.cpp345
-rw-r--r--qpid/cpp/src/qpid/broker/Broker.h157
-rw-r--r--qpid/cpp/src/qpid/broker/BrokerAdapter.cpp353
-rw-r--r--qpid/cpp/src/qpid/broker/BrokerAdapter.h208
-rw-r--r--qpid/cpp/src/qpid/broker/BrokerSingleton.cpp36
-rw-r--r--qpid/cpp/src/qpid/broker/BrokerSingleton.h52
-rw-r--r--qpid/cpp/src/qpid/broker/Connection.cpp328
-rw-r--r--qpid/cpp/src/qpid/broker/Connection.h115
-rw-r--r--qpid/cpp/src/qpid/broker/ConnectionFactory.cpp53
-rw-r--r--qpid/cpp/src/qpid/broker/ConnectionFactory.h49
-rw-r--r--qpid/cpp/src/qpid/broker/ConnectionHandler.cpp166
-rw-r--r--qpid/cpp/src/qpid/broker/ConnectionHandler.h91
-rw-r--r--qpid/cpp/src/qpid/broker/ConnectionState.h84
-rw-r--r--qpid/cpp/src/qpid/broker/ConnectionToken.h40
-rw-r--r--qpid/cpp/src/qpid/broker/Consumer.h65
-rw-r--r--qpid/cpp/src/qpid/broker/Daemon.cpp192
-rw-r--r--qpid/cpp/src/qpid/broker/Daemon.h81
-rw-r--r--qpid/cpp/src/qpid/broker/Deliverable.h40
-rw-r--r--qpid/cpp/src/qpid/broker/DeliverableMessage.cpp43
-rw-r--r--qpid/cpp/src/qpid/broker/DeliverableMessage.h45
-rw-r--r--qpid/cpp/src/qpid/broker/DeliveryAdapter.h52
-rw-r--r--qpid/cpp/src/qpid/broker/DeliveryId.h35
-rw-r--r--qpid/cpp/src/qpid/broker/DeliveryRecord.cpp211
-rw-r--r--qpid/cpp/src/qpid/broker/DeliveryRecord.h118
-rw-r--r--qpid/cpp/src/qpid/broker/DeliveryToken.h45
-rw-r--r--qpid/cpp/src/qpid/broker/DirectExchange.cpp153
-rw-r--r--qpid/cpp/src/qpid/broker/DirectExchange.h62
-rw-r--r--qpid/cpp/src/qpid/broker/DtxAck.cpp58
-rw-r--r--qpid/cpp/src/qpid/broker/DtxAck.h47
-rw-r--r--qpid/cpp/src/qpid/broker/DtxBuffer.cpp83
-rw-r--r--qpid/cpp/src/qpid/broker/DtxBuffer.h56
-rw-r--r--qpid/cpp/src/qpid/broker/DtxHandlerImpl.cpp171
-rw-r--r--qpid/cpp/src/qpid/broker/DtxHandlerImpl.h67
-rw-r--r--qpid/cpp/src/qpid/broker/DtxManager.cpp172
-rw-r--r--qpid/cpp/src/qpid/broker/DtxManager.h74
-rw-r--r--qpid/cpp/src/qpid/broker/DtxTimeout.cpp35
-rw-r--r--qpid/cpp/src/qpid/broker/DtxTimeout.h48
-rw-r--r--qpid/cpp/src/qpid/broker/DtxWorkRecord.cpp177
-rw-r--r--qpid/cpp/src/qpid/broker/DtxWorkRecord.h79
-rw-r--r--qpid/cpp/src/qpid/broker/Exchange.cpp141
-rw-r--r--qpid/cpp/src/qpid/broker/Exchange.h109
-rw-r--r--qpid/cpp/src/qpid/broker/ExchangeRegistry.cpp92
-rw-r--r--qpid/cpp/src/qpid/broker/ExchangeRegistry.h61
-rw-r--r--qpid/cpp/src/qpid/broker/FanOutExchange.cpp126
-rw-r--r--qpid/cpp/src/qpid/broker/FanOutExchange.h64
-rw-r--r--qpid/cpp/src/qpid/broker/HandlerImpl.h53
-rw-r--r--qpid/cpp/src/qpid/broker/HeadersExchange.cpp231
-rw-r--r--qpid/cpp/src/qpid/broker/HeadersExchange.h72
-rw-r--r--qpid/cpp/src/qpid/broker/IncomingExecutionContext.cpp143
-rw-r--r--qpid/cpp/src/qpid/broker/IncomingExecutionContext.h61
-rw-r--r--qpid/cpp/src/qpid/broker/IncompleteMessageList.cpp51
-rw-r--r--qpid/cpp/src/qpid/broker/IncompleteMessageList.h48
-rw-r--r--qpid/cpp/src/qpid/broker/Message.cpp249
-rw-r--r--qpid/cpp/src/qpid/broker/Message.h145
-rw-r--r--qpid/cpp/src/qpid/broker/MessageAdapter.cpp89
-rw-r--r--qpid/cpp/src/qpid/broker/MessageAdapter.h71
-rw-r--r--qpid/cpp/src/qpid/broker/MessageBuilder.cpp123
-rw-r--r--qpid/cpp/src/qpid/broker/MessageBuilder.h57
-rw-r--r--qpid/cpp/src/qpid/broker/MessageDelivery.cpp151
-rw-r--r--qpid/cpp/src/qpid/broker/MessageDelivery.h58
-rw-r--r--qpid/cpp/src/qpid/broker/MessageHandlerImpl.cpp210
-rw-r--r--qpid/cpp/src/qpid/broker/MessageHandlerImpl.h110
-rw-r--r--qpid/cpp/src/qpid/broker/MessageStore.h195
-rw-r--r--qpid/cpp/src/qpid/broker/MessageStoreModule.cpp147
-rw-r--r--qpid/cpp/src/qpid/broker/MessageStoreModule.h82
-rw-r--r--qpid/cpp/src/qpid/broker/NameGenerator.cpp32
-rw-r--r--qpid/cpp/src/qpid/broker/NameGenerator.h39
-rw-r--r--qpid/cpp/src/qpid/broker/NullMessageStore.cpp151
-rw-r--r--qpid/cpp/src/qpid/broker/NullMessageStore.h81
-rw-r--r--qpid/cpp/src/qpid/broker/OwnershipToken.h38
-rw-r--r--qpid/cpp/src/qpid/broker/Persistable.h63
-rw-r--r--qpid/cpp/src/qpid/broker/PersistableExchange.h45
-rw-r--r--qpid/cpp/src/qpid/broker/PersistableMessage.cpp48
-rw-r--r--qpid/cpp/src/qpid/broker/PersistableMessage.h188
-rw-r--r--qpid/cpp/src/qpid/broker/PersistableQueue.h87
-rw-r--r--qpid/cpp/src/qpid/broker/Prefetch.h42
-rw-r--r--qpid/cpp/src/qpid/broker/PreviewConnection.cpp341
-rw-r--r--qpid/cpp/src/qpid/broker/PreviewConnection.h128
-rw-r--r--qpid/cpp/src/qpid/broker/PreviewConnectionCodec.cpp91
-rw-r--r--qpid/cpp/src/qpid/broker/PreviewConnectionCodec.h55
-rw-r--r--qpid/cpp/src/qpid/broker/PreviewConnectionHandler.cpp212
-rw-r--r--qpid/cpp/src/qpid/broker/PreviewConnectionHandler.h91
-rw-r--r--qpid/cpp/src/qpid/broker/PreviewSessionHandler.cpp210
-rw-r--r--qpid/cpp/src/qpid/broker/PreviewSessionHandler.h111
-rw-r--r--qpid/cpp/src/qpid/broker/PreviewSessionManager.cpp113
-rw-r--r--qpid/cpp/src/qpid/broker/PreviewSessionManager.h101
-rw-r--r--qpid/cpp/src/qpid/broker/PreviewSessionState.cpp174
-rw-r--r--qpid/cpp/src/qpid/broker/PreviewSessionState.h125
-rw-r--r--qpid/cpp/src/qpid/broker/Queue.cpp661
-rw-r--r--qpid/cpp/src/qpid/broker/Queue.h198
-rw-r--r--qpid/cpp/src/qpid/broker/QueueBindings.cpp45
-rw-r--r--qpid/cpp/src/qpid/broker/QueueBindings.h55
-rw-r--r--qpid/cpp/src/qpid/broker/QueuePolicy.cpp70
-rw-r--r--qpid/cpp/src/qpid/broker/QueuePolicy.h54
-rw-r--r--qpid/cpp/src/qpid/broker/QueueRegistry.cpp93
-rw-r--r--qpid/cpp/src/qpid/broker/QueueRegistry.h119
-rw-r--r--qpid/cpp/src/qpid/broker/RecoverableExchange.h50
-rw-r--r--qpid/cpp/src/qpid/broker/RecoverableMessage.h58
-rw-r--r--qpid/cpp/src/qpid/broker/RecoverableQueue.h59
-rw-r--r--qpid/cpp/src/qpid/broker/RecoverableTransaction.h49
-rw-r--r--qpid/cpp/src/qpid/broker/RecoveredDequeue.cpp40
-rw-r--r--qpid/cpp/src/qpid/broker/RecoveredDequeue.h53
-rw-r--r--qpid/cpp/src/qpid/broker/RecoveredEnqueue.cpp40
-rw-r--r--qpid/cpp/src/qpid/broker/RecoveredEnqueue.h53
-rw-r--r--qpid/cpp/src/qpid/broker/RecoveryManager.h58
-rw-r--r--qpid/cpp/src/qpid/broker/RecoveryManagerImpl.cpp222
-rw-r--r--qpid/cpp/src/qpid/broker/RecoveryManagerImpl.h55
-rw-r--r--qpid/cpp/src/qpid/broker/SemanticHandler.cpp196
-rw-r--r--qpid/cpp/src/qpid/broker/SemanticHandler.h102
-rw-r--r--qpid/cpp/src/qpid/broker/SemanticState.cpp696
-rw-r--r--qpid/cpp/src/qpid/broker/SemanticState.h200
-rw-r--r--qpid/cpp/src/qpid/broker/SessionAdapter.cpp590
-rw-r--r--qpid/cpp/src/qpid/broker/SessionAdapter.h269
-rw-r--r--qpid/cpp/src/qpid/broker/SessionContext.h51
-rw-r--r--qpid/cpp/src/qpid/broker/SessionHandler.cpp228
-rw-r--r--qpid/cpp/src/qpid/broker/SessionHandler.h116
-rw-r--r--qpid/cpp/src/qpid/broker/SessionManager.cpp113
-rw-r--r--qpid/cpp/src/qpid/broker/SessionManager.h101
-rw-r--r--qpid/cpp/src/qpid/broker/SessionState.cpp288
-rw-r--r--qpid/cpp/src/qpid/broker/SessionState.h159
-rw-r--r--qpid/cpp/src/qpid/broker/System.cpp48
-rw-r--r--qpid/cpp/src/qpid/broker/System.h51
-rw-r--r--qpid/cpp/src/qpid/broker/Timer.cpp103
-rw-r--r--qpid/cpp/src/qpid/broker/Timer.h79
-rw-r--r--qpid/cpp/src/qpid/broker/TopicExchange.cpp242
-rw-r--r--qpid/cpp/src/qpid/broker/TopicExchange.h104
-rw-r--r--qpid/cpp/src/qpid/broker/TransactionalStore.h60
-rw-r--r--qpid/cpp/src/qpid/broker/TxAccept.cpp61
-rw-r--r--qpid/cpp/src/qpid/broker/TxAccept.h57
-rw-r--r--qpid/cpp/src/qpid/broker/TxAck.cpp59
-rw-r--r--qpid/cpp/src/qpid/broker/TxAck.h57
-rw-r--r--qpid/cpp/src/qpid/broker/TxBuffer.cpp67
-rw-r--r--qpid/cpp/src/qpid/broker/TxBuffer.h115
-rw-r--r--qpid/cpp/src/qpid/broker/TxOp.h42
-rw-r--r--qpid/cpp/src/qpid/broker/TxPublish.cpp78
-rw-r--r--qpid/cpp/src/qpid/broker/TxPublish.h83
-rw-r--r--qpid/cpp/src/qpid/broker/Vhost.cpp40
-rw-r--r--qpid/cpp/src/qpid/broker/Vhost.h51
-rw-r--r--qpid/cpp/src/qpid/client/AckMode.h53
-rw-r--r--qpid/cpp/src/qpid/client/AckPolicy.h56
-rw-r--r--qpid/cpp/src/qpid/client/ChainableFrameHandler.h47
-rw-r--r--qpid/cpp/src/qpid/client/Channel.cpp268
-rw-r--r--qpid/cpp/src/qpid/client/Channel.h316
-rw-r--r--qpid/cpp/src/qpid/client/Completion.h64
-rw-r--r--qpid/cpp/src/qpid/client/CompletionTracker.cpp121
-rw-r--r--qpid/cpp/src/qpid/client/CompletionTracker.h77
-rw-r--r--qpid/cpp/src/qpid/client/Connection.cpp97
-rw-r--r--qpid/cpp/src/qpid/client/Connection.h149
-rw-r--r--qpid/cpp/src/qpid/client/ConnectionHandler.cpp209
-rw-r--r--qpid/cpp/src/qpid/client/ConnectionHandler.h85
-rw-r--r--qpid/cpp/src/qpid/client/ConnectionImpl.cpp158
-rw-r--r--qpid/cpp/src/qpid/client/ConnectionImpl.h87
-rw-r--r--qpid/cpp/src/qpid/client/Connector.cpp297
-rw-r--r--qpid/cpp/src/qpid/client/Connector.h143
-rw-r--r--qpid/cpp/src/qpid/client/Correlator.cpp45
-rw-r--r--qpid/cpp/src/qpid/client/Correlator.h52
-rw-r--r--qpid/cpp/src/qpid/client/Demux.cpp132
-rw-r--r--qpid/cpp/src/qpid/client/Demux.h100
-rw-r--r--qpid/cpp/src/qpid/client/Dispatcher.cpp142
-rw-r--r--qpid/cpp/src/qpid/client/Dispatcher.h84
-rw-r--r--qpid/cpp/src/qpid/client/Exchange.cpp34
-rw-r--r--qpid/cpp/src/qpid/client/Exchange.h106
-rw-r--r--qpid/cpp/src/qpid/client/Execution.h50
-rw-r--r--qpid/cpp/src/qpid/client/ExecutionHandler.cpp267
-rw-r--r--qpid/cpp/src/qpid/client/ExecutionHandler.h104
-rw-r--r--qpid/cpp/src/qpid/client/Future.h108
-rw-r--r--qpid/cpp/src/qpid/client/FutureCompletion.cpp48
-rw-r--r--qpid/cpp/src/qpid/client/FutureCompletion.h48
-rw-r--r--qpid/cpp/src/qpid/client/FutureFactory.cpp51
-rw-r--r--qpid/cpp/src/qpid/client/FutureFactory.h48
-rw-r--r--qpid/cpp/src/qpid/client/FutureResponse.cpp45
-rw-r--r--qpid/cpp/src/qpid/client/FutureResponse.h46
-rw-r--r--qpid/cpp/src/qpid/client/FutureResult.cpp43
-rw-r--r--qpid/cpp/src/qpid/client/FutureResult.h46
-rw-r--r--qpid/cpp/src/qpid/client/LocalQueue.cpp64
-rw-r--r--qpid/cpp/src/qpid/client/LocalQueue.h60
-rw-r--r--qpid/cpp/src/qpid/client/Message.h104
-rw-r--r--qpid/cpp/src/qpid/client/MessageListener.cpp24
-rw-r--r--qpid/cpp/src/qpid/client/MessageListener.h49
-rw-r--r--qpid/cpp/src/qpid/client/MessageQueue.h50
-rw-r--r--qpid/cpp/src/qpid/client/Queue.cpp58
-rw-r--r--qpid/cpp/src/qpid/client/Queue.h103
-rw-r--r--qpid/cpp/src/qpid/client/Response.h52
-rw-r--r--qpid/cpp/src/qpid/client/Session.h38
-rw-r--r--qpid/cpp/src/qpid/client/SessionBase.cpp50
-rw-r--r--qpid/cpp/src/qpid/client/SessionBase.h134
-rw-r--r--qpid/cpp/src/qpid/client/SessionCore.cpp440
-rw-r--r--qpid/cpp/src/qpid/client/SessionCore.h141
-rw-r--r--qpid/cpp/src/qpid/client/StateManager.cpp68
-rw-r--r--qpid/cpp/src/qpid/client/StateManager.h46
-rw-r--r--qpid/cpp/src/qpid/client/SubscriptionManager.cpp111
-rw-r--r--qpid/cpp/src/qpid/client/SubscriptionManager.h141
-rw-r--r--qpid/cpp/src/qpid/client/TypedResult.h51
-rw-r--r--qpid/cpp/src/qpid/cluster/ClassifierHandler.cpp51
-rw-r--r--qpid/cpp/src/qpid/cluster/ClassifierHandler.h50
-rw-r--r--qpid/cpp/src/qpid/cluster/Cluster.cpp260
-rw-r--r--qpid/cpp/src/qpid/cluster/Cluster.h131
-rw-r--r--qpid/cpp/src/qpid/cluster/ClusterPlugin.cpp79
-rw-r--r--qpid/cpp/src/qpid/cluster/Cpg.cpp176
-rw-r--r--qpid/cpp/src/qpid/cluster/Cpg.h185
-rw-r--r--qpid/cpp/src/qpid/cluster/Dispatchable.h52
-rw-r--r--qpid/cpp/src/qpid/doxygen_mainpage.h45
-rw-r--r--qpid/cpp/src/qpid/framing/AMQBody.cpp64
-rw-r--r--qpid/cpp/src/qpid/framing/AMQBody.h78
-rw-r--r--qpid/cpp/src/qpid/framing/AMQCommandControlBody.h70
-rw-r--r--qpid/cpp/src/qpid/framing/AMQContentBody.cpp44
-rw-r--r--qpid/cpp/src/qpid/framing/AMQContentBody.h53
-rw-r--r--qpid/cpp/src/qpid/framing/AMQDataBlock.h42
-rw-r--r--qpid/cpp/src/qpid/framing/AMQFrame.cpp123
-rw-r--r--qpid/cpp/src/qpid/framing/AMQFrame.h112
-rw-r--r--qpid/cpp/src/qpid/framing/AMQHeaderBody.cpp63
-rw-r--r--qpid/cpp/src/qpid/framing/AMQHeaderBody.h113
-rw-r--r--qpid/cpp/src/qpid/framing/AMQHeartbeatBody.cpp29
-rw-r--r--qpid/cpp/src/qpid/framing/AMQHeartbeatBody.h46
-rw-r--r--qpid/cpp/src/qpid/framing/AMQMethodBody.cpp28
-rw-r--r--qpid/cpp/src/qpid/framing/AMQMethodBody.h72
-rw-r--r--qpid/cpp/src/qpid/framing/AMQP_HighestVersion.h41
-rw-r--r--qpid/cpp/src/qpid/framing/AccumulatedAck.cpp164
-rw-r--r--qpid/cpp/src/qpid/framing/AccumulatedAck.h76
-rw-r--r--qpid/cpp/src/qpid/framing/Array.cpp127
-rw-r--r--qpid/cpp/src/qpid/framing/Array.h78
-rw-r--r--qpid/cpp/src/qpid/framing/Blob.cpp31
-rw-r--r--qpid/cpp/src/qpid/framing/Blob.h193
-rw-r--r--qpid/cpp/src/qpid/framing/BodyHandler.cpp55
-rw-r--r--qpid/cpp/src/qpid/framing/BodyHandler.h56
-rw-r--r--qpid/cpp/src/qpid/framing/BodyHolder.cpp76
-rw-r--r--qpid/cpp/src/qpid/framing/BodyHolder.h88
-rw-r--r--qpid/cpp/src/qpid/framing/Buffer.cpp276
-rw-r--r--qpid/cpp/src/qpid/framing/Buffer.h124
-rw-r--r--qpid/cpp/src/qpid/framing/ChannelHandler.h53
-rw-r--r--qpid/cpp/src/qpid/framing/FieldTable.cpp165
-rw-r--r--qpid/cpp/src/qpid/framing/FieldTable.h96
-rw-r--r--qpid/cpp/src/qpid/framing/FieldValue.cpp136
-rw-r--r--qpid/cpp/src/qpid/framing/FieldValue.h235
-rw-r--r--qpid/cpp/src/qpid/framing/FrameDefaultVisitor.h60
-rw-r--r--qpid/cpp/src/qpid/framing/FrameHandler.h33
-rw-r--r--qpid/cpp/src/qpid/framing/FrameSet.cpp84
-rw-r--r--qpid/cpp/src/qpid/framing/FrameSet.h105
-rw-r--r--qpid/cpp/src/qpid/framing/FramingContent.cpp73
-rw-r--r--qpid/cpp/src/qpid/framing/FramingContent.h63
-rw-r--r--qpid/cpp/src/qpid/framing/Handler.h122
-rw-r--r--qpid/cpp/src/qpid/framing/HeaderProperties.h46
-rw-r--r--qpid/cpp/src/qpid/framing/InitiationHandler.cpp24
-rw-r--r--qpid/cpp/src/qpid/framing/InitiationHandler.h41
-rw-r--r--qpid/cpp/src/qpid/framing/InputHandler.h41
-rw-r--r--qpid/cpp/src/qpid/framing/Invoker.h86
-rw-r--r--qpid/cpp/src/qpid/framing/MethodContent.h40
-rw-r--r--qpid/cpp/src/qpid/framing/ModelMethod.h49
-rw-r--r--qpid/cpp/src/qpid/framing/OutputHandler.h42
-rw-r--r--qpid/cpp/src/qpid/framing/ProtocolInitiation.cpp66
-rw-r--r--qpid/cpp/src/qpid/framing/ProtocolInitiation.h58
-rw-r--r--qpid/cpp/src/qpid/framing/ProtocolVersion.cpp44
-rw-r--r--qpid/cpp/src/qpid/framing/ProtocolVersion.h57
-rw-r--r--qpid/cpp/src/qpid/framing/Proxy.cpp37
-rw-r--r--qpid/cpp/src/qpid/framing/Proxy.h52
-rw-r--r--qpid/cpp/src/qpid/framing/SendContent.cpp69
-rw-r--r--qpid/cpp/src/qpid/framing/SendContent.h55
-rw-r--r--qpid/cpp/src/qpid/framing/SequenceNumber.cpp89
-rw-r--r--qpid/cpp/src/qpid/framing/SequenceNumber.h66
-rw-r--r--qpid/cpp/src/qpid/framing/SequenceNumberSet.cpp89
-rw-r--r--qpid/cpp/src/qpid/framing/SequenceNumberSet.h68
-rw-r--r--qpid/cpp/src/qpid/framing/SequenceSet.cpp226
-rw-r--r--qpid/cpp/src/qpid/framing/SequenceSet.h86
-rw-r--r--qpid/cpp/src/qpid/framing/SerializeHandler.h49
-rw-r--r--qpid/cpp/src/qpid/framing/SessionState.cpp137
-rw-r--r--qpid/cpp/src/qpid/framing/SessionState.h138
-rw-r--r--qpid/cpp/src/qpid/framing/StructHelper.h56
-rw-r--r--qpid/cpp/src/qpid/framing/TemplateVisitor.h89
-rw-r--r--qpid/cpp/src/qpid/framing/TransferContent.cpp102
-rw-r--r--qpid/cpp/src/qpid/framing/TransferContent.h58
-rw-r--r--qpid/cpp/src/qpid/framing/TypeFilter.h51
-rw-r--r--qpid/cpp/src/qpid/framing/Uuid.cpp61
-rw-r--r--qpid/cpp/src/qpid/framing/Uuid.h84
-rw-r--r--qpid/cpp/src/qpid/framing/Visitor.h91
-rw-r--r--qpid/cpp/src/qpid/framing/amqp_framing.h32
-rw-r--r--qpid/cpp/src/qpid/framing/amqp_types.h72
-rw-r--r--qpid/cpp/src/qpid/framing/amqp_types_full.h40
-rw-r--r--qpid/cpp/src/qpid/framing/frame_functors.h116
-rw-r--r--qpid/cpp/src/qpid/framing/variant.h91
-rw-r--r--qpid/cpp/src/qpid/log/Helpers.h79
-rw-r--r--qpid/cpp/src/qpid/log/Logger.cpp229
-rw-r--r--qpid/cpp/src/qpid/log/Logger.h113
-rw-r--r--qpid/cpp/src/qpid/log/Options.cpp66
-rw-r--r--qpid/cpp/src/qpid/log/Options.h42
-rw-r--r--qpid/cpp/src/qpid/log/Selector.cpp66
-rw-r--r--qpid/cpp/src/qpid/log/Selector.h70
-rw-r--r--qpid/cpp/src/qpid/log/Statement.cpp92
-rw-r--r--qpid/cpp/src/qpid/log/Statement.h114
-rw-r--r--qpid/cpp/src/qpid/management/Args.h44
-rw-r--r--qpid/cpp/src/qpid/management/Manageable.cpp37
-rw-r--r--qpid/cpp/src/qpid/management/Manageable.h68
-rw-r--r--qpid/cpp/src/qpid/management/ManagementAgent.cpp669
-rw-r--r--qpid/cpp/src/qpid/management/ManagementAgent.h189
-rw-r--r--qpid/cpp/src/qpid/management/ManagementExchange.cpp65
-rw-r--r--qpid/cpp/src/qpid/management/ManagementExchange.h58
-rw-r--r--qpid/cpp/src/qpid/management/ManagementObject.cpp39
-rw-r--r--qpid/cpp/src/qpid/management/ManagementObject.h125
-rw-r--r--qpid/cpp/src/qpid/memory.h32
-rw-r--r--qpid/cpp/src/qpid/pointer_to_other.h62
-rw-r--r--qpid/cpp/src/qpid/ptr_map.h120
-rw-r--r--qpid/cpp/src/qpid/shared_ptr.h51
-rw-r--r--qpid/cpp/src/qpid/sys/Acceptor.h53
-rw-r--r--qpid/cpp/src/qpid/sys/AggregateOutput.cpp62
-rw-r--r--qpid/cpp/src/qpid/sys/AggregateOutput.h54
-rw-r--r--qpid/cpp/src/qpid/sys/AsynchIO.h134
-rw-r--r--qpid/cpp/src/qpid/sys/AsynchIOAcceptor.cpp316
-rw-r--r--qpid/cpp/src/qpid/sys/AtomicCount.h53
-rw-r--r--qpid/cpp/src/qpid/sys/BlockingQueue.h142
-rw-r--r--qpid/cpp/src/qpid/sys/Condition.h31
-rw-r--r--qpid/cpp/src/qpid/sys/ConnectionCodec.h80
-rw-r--r--qpid/cpp/src/qpid/sys/ConnectionInputHandler.h43
-rw-r--r--qpid/cpp/src/qpid/sys/ConnectionInputHandlerFactory.h53
-rw-r--r--qpid/cpp/src/qpid/sys/ConnectionOutputHandler.h42
-rw-r--r--qpid/cpp/src/qpid/sys/DeletionManager.h138
-rw-r--r--qpid/cpp/src/qpid/sys/Dispatcher.cpp441
-rw-r--r--qpid/cpp/src/qpid/sys/Dispatcher.h96
-rw-r--r--qpid/cpp/src/qpid/sys/Module.h50
-rw-r--r--qpid/cpp/src/qpid/sys/Monitor.h51
-rw-r--r--qpid/cpp/src/qpid/sys/Mutex.h89
-rw-r--r--qpid/cpp/src/qpid/sys/OutputControl.h38
-rw-r--r--qpid/cpp/src/qpid/sys/OutputTask.h38
-rw-r--r--qpid/cpp/src/qpid/sys/Poller.h110
-rw-r--r--qpid/cpp/src/qpid/sys/Runnable.cpp32
-rw-r--r--qpid/cpp/src/qpid/sys/Runnable.h50
-rw-r--r--qpid/cpp/src/qpid/sys/ScopedIncrement.h67
-rw-r--r--qpid/cpp/src/qpid/sys/Semaphore.h67
-rw-r--r--qpid/cpp/src/qpid/sys/Serializer.cpp71
-rw-r--r--qpid/cpp/src/qpid/sys/Serializer.h181
-rw-r--r--qpid/cpp/src/qpid/sys/Shlib.cpp38
-rw-r--r--qpid/cpp/src/qpid/sys/Shlib.h76
-rw-r--r--qpid/cpp/src/qpid/sys/ShutdownHandler.h37
-rw-r--r--qpid/cpp/src/qpid/sys/Socket.h116
-rw-r--r--qpid/cpp/src/qpid/sys/StateMonitor.h78
-rw-r--r--qpid/cpp/src/qpid/sys/SystemInfo.cpp35
-rw-r--r--qpid/cpp/src/qpid/sys/SystemInfo.h44
-rw-r--r--qpid/cpp/src/qpid/sys/Thread.h31
-rw-r--r--qpid/cpp/src/qpid/sys/Time.h154
-rw-r--r--qpid/cpp/src/qpid/sys/TimeoutHandler.h39
-rw-r--r--qpid/cpp/src/qpid/sys/Waitable.h71
-rw-r--r--qpid/cpp/src/qpid/sys/apr/APRBase.cpp89
-rw-r--r--qpid/cpp/src/qpid/sys/apr/APRBase.h74
-rw-r--r--qpid/cpp/src/qpid/sys/apr/APRPool.cpp41
-rw-r--r--qpid/cpp/src/qpid/sys/apr/APRPool.h50
-rw-r--r--qpid/cpp/src/qpid/sys/apr/Condition.h84
-rw-r--r--qpid/cpp/src/qpid/sys/apr/Mutex.h124
-rw-r--r--qpid/cpp/src/qpid/sys/apr/Shlib.cpp49
-rw-r--r--qpid/cpp/src/qpid/sys/apr/Socket.cpp114
-rw-r--r--qpid/cpp/src/qpid/sys/apr/Thread.cpp34
-rw-r--r--qpid/cpp/src/qpid/sys/apr/Thread.h106
-rw-r--r--qpid/cpp/src/qpid/sys/apr/Time.cpp36
-rw-r--r--qpid/cpp/src/qpid/sys/epoll/EpollPoller.cpp338
-rw-r--r--qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp364
-rw-r--r--qpid/cpp/src/qpid/sys/posix/Condition.h86
-rw-r--r--qpid/cpp/src/qpid/sys/posix/Mutex.h201
-rw-r--r--qpid/cpp/src/qpid/sys/posix/PrivatePosix.h44
-rw-r--r--qpid/cpp/src/qpid/sys/posix/Shlib.cpp59
-rw-r--r--qpid/cpp/src/qpid/sys/posix/Socket.cpp283
-rw-r--r--qpid/cpp/src/qpid/sys/posix/Thread.cpp29
-rw-r--r--qpid/cpp/src/qpid/sys/posix/Thread.h92
-rw-r--r--qpid/cpp/src/qpid/sys/posix/Time.cpp81
-rw-r--r--qpid/cpp/src/qpid/sys/posix/check.h47
-rw-r--r--qpid/cpp/src/qpidd.cpp260
-rw-r--r--qpid/cpp/src/tests/.valgrind.supp32
-rw-r--r--qpid/cpp/src/tests/.valgrindrc7
-rw-r--r--qpid/cpp/src/tests/AccumulatedAckTest.cpp250
-rw-r--r--qpid/cpp/src/tests/Array.cpp79
-rw-r--r--qpid/cpp/src/tests/BasicP2PTest.cpp66
-rw-r--r--qpid/cpp/src/tests/BasicP2PTest.h46
-rw-r--r--qpid/cpp/src/tests/BasicPubSubTest.cpp121
-rw-r--r--qpid/cpp/src/tests/BasicPubSubTest.h51
-rw-r--r--qpid/cpp/src/tests/Blob.cpp128
-rw-r--r--qpid/cpp/src/tests/BrokerFixture.h108
-rw-r--r--qpid/cpp/src/tests/ClientChannelTest.cpp220
-rw-r--r--qpid/cpp/src/tests/ClientSessionTest.cpp220
-rw-r--r--qpid/cpp/src/tests/ConcurrentQueue.cpp208
-rw-r--r--qpid/cpp/src/tests/Cpg.cpp115
-rw-r--r--qpid/cpp/src/tests/DeliveryRecordTest.cpp68
-rw-r--r--qpid/cpp/src/tests/DispatcherTest.cpp128
-rw-r--r--qpid/cpp/src/tests/DtxWorkRecordTest.cpp202
-rw-r--r--qpid/cpp/src/tests/EventChannelTest.cpp187
-rw-r--r--qpid/cpp/src/tests/EventChannelThreadsTest.cpp247
-rw-r--r--qpid/cpp/src/tests/ExchangeTest.cpp179
-rw-r--r--qpid/cpp/src/tests/FieldTable.cpp84
-rw-r--r--qpid/cpp/src/tests/FieldValue.cpp90
-rw-r--r--qpid/cpp/src/tests/Frame.cpp80
-rw-r--r--qpid/cpp/src/tests/FramingTest.cpp232
-rw-r--r--qpid/cpp/src/tests/HeaderTest.cpp126
-rw-r--r--qpid/cpp/src/tests/HeadersExchangeTest.cpp131
-rw-r--r--qpid/cpp/src/tests/IList.cpp164
-rw-r--r--qpid/cpp/src/tests/ISList.cpp209
-rw-r--r--qpid/cpp/src/tests/IncompleteMessageList.cpp128
-rw-r--r--qpid/cpp/src/tests/InlineVector.cpp89
-rw-r--r--qpid/cpp/src/tests/Makefile.am182
-rw-r--r--qpid/cpp/src/tests/MessageBuilderTest.cpp224
-rw-r--r--qpid/cpp/src/tests/MessageTest.cpp97
-rw-r--r--qpid/cpp/src/tests/MessageUtils.h54
-rw-r--r--qpid/cpp/src/tests/MockConnectionInputHandler.h100
-rw-r--r--qpid/cpp/src/tests/PollerTest.cpp164
-rw-r--r--qpid/cpp/src/tests/QueuePolicyTest.cpp89
-rw-r--r--qpid/cpp/src/tests/QueueRegistryTest.cpp95
-rw-r--r--qpid/cpp/src/tests/QueueTest.cpp258
-rw-r--r--qpid/cpp/src/tests/README71
-rw-r--r--qpid/cpp/src/tests/RefCounted.cpp50
-rw-r--r--qpid/cpp/src/tests/SequenceNumberTest.cpp220
-rw-r--r--qpid/cpp/src/tests/SequenceSet.cpp139
-rw-r--r--qpid/cpp/src/tests/Serializer.cpp157
-rw-r--r--qpid/cpp/src/tests/SessionState.cpp146
-rw-r--r--qpid/cpp/src/tests/Shlib.cpp60
-rw-r--r--qpid/cpp/src/tests/SimpleTestCaseBase.cpp87
-rw-r--r--qpid/cpp/src/tests/SimpleTestCaseBase.h88
-rw-r--r--qpid/cpp/src/tests/SocketProxy.h164
-rw-r--r--qpid/cpp/src/tests/TestCase.h64
-rw-r--r--qpid/cpp/src/tests/TestOptions.h94
-rw-r--r--qpid/cpp/src/tests/TimerTest.cpp130
-rw-r--r--qpid/cpp/src/tests/TopicExchangeTest.cpp200
-rw-r--r--qpid/cpp/src/tests/TxAckTest.cpp119
-rw-r--r--qpid/cpp/src/tests/TxBufferTest.cpp185
-rw-r--r--qpid/cpp/src/tests/TxMocks.h226
-rw-r--r--qpid/cpp/src/tests/TxPublishTest.cpp114
-rw-r--r--qpid/cpp/src/tests/Url.cpp64
-rw-r--r--qpid/cpp/src/tests/Uuid.cpp78
-rwxr-xr-xqpid/cpp/src/tests/ais_check27
-rwxr-xr-xqpid/cpp/src/tests/ais_run15
-rw-r--r--qpid/cpp/src/tests/ais_test.cpp23
-rw-r--r--qpid/cpp/src/tests/amqp_0_10/Map.cpp96
-rw-r--r--qpid/cpp/src/tests/amqp_0_10/ProxyTemplate.cpp49
-rw-r--r--qpid/cpp/src/tests/amqp_0_10/apply.cpp99
-rw-r--r--qpid/cpp/src/tests/amqp_0_10/handlers.cpp125
-rw-r--r--qpid/cpp/src/tests/amqp_0_10/serialize.cpp383
-rw-r--r--qpid/cpp/src/tests/client_test.cpp147
-rw-r--r--qpid/cpp/src/tests/cluster.mk20
-rw-r--r--qpid/cpp/src/tests/cluster_client.cpp84
-rw-r--r--qpid/cpp/src/tests/dlclose_noop.c30
-rw-r--r--qpid/cpp/src/tests/echo_service.cpp229
-rw-r--r--qpid/cpp/src/tests/exception_test.cpp99
-rwxr-xr-xqpid/cpp/src/tests/fanout_perftest2
-rwxr-xr-xqpid/cpp/src/tests/federation.py191
-rw-r--r--qpid/cpp/src/tests/interop_runner.cpp240
-rw-r--r--qpid/cpp/src/tests/latencytest.cpp372
-rw-r--r--qpid/cpp/src/tests/logging.cpp384
-rwxr-xr-xqpid/cpp/src/tests/multiq_perftest2
-rwxr-xr-xqpid/cpp/src/tests/perfdist50
-rw-r--r--qpid/cpp/src/tests/perftest.cpp640
-rwxr-xr-xqpid/cpp/src/tests/python_tests20
-rw-r--r--qpid/cpp/src/tests/qpid_test_plugin.h43
-rwxr-xr-xqpid/cpp/src/tests/quick_perftest2
-rwxr-xr-xqpid/cpp/src/tests/quick_topictest9
-rwxr-xr-xqpid/cpp/src/tests/run-unit-tests28
-rwxr-xr-xqpid/cpp/src/tests/run_federation_tests24
-rwxr-xr-xqpid/cpp/src/tests/run_perftest8
-rwxr-xr-xqpid/cpp/src/tests/run_test51
-rwxr-xr-xqpid/cpp/src/tests/shared_perftest2
-rw-r--r--qpid/cpp/src/tests/shlibtest.cpp28
-rwxr-xr-xqpid/cpp/src/tests/start_broker4
-rwxr-xr-xqpid/cpp/src/tests/start_cluster19
-rwxr-xr-xqpid/cpp/src/tests/stop_broker20
-rwxr-xr-xqpid/cpp/src/tests/stop_cluster14
-rw-r--r--qpid/cpp/src/tests/test_tools.h78
-rw-r--r--qpid/cpp/src/tests/topic_listener.cpp189
-rwxr-xr-xqpid/cpp/src/tests/topic_perftest2
-rw-r--r--qpid/cpp/src/tests/topic_publisher.cpp206
-rwxr-xr-xqpid/cpp/src/tests/topictest40
-rw-r--r--qpid/cpp/src/tests/txtest.cpp270
-rw-r--r--qpid/cpp/src/tests/unit_test.cpp23
-rw-r--r--qpid/cpp/src/tests/unit_test.h46
-rw-r--r--qpid/cpp/src/tests/vg_check23
-rwxr-xr-xqpid/cpp/versions12
-rw-r--r--qpid/cpp/xml/cluster.xml37
-rw-r--r--qpid/cpp/xml/extra.xml938
626 files changed, 79050 insertions, 0 deletions
diff --git a/qpid/cpp/DESIGN b/qpid/cpp/DESIGN
new file mode 100644
index 0000000000..7e9ba6755c
--- /dev/null
+++ b/qpid/cpp/DESIGN
@@ -0,0 +1,79 @@
+Qpid C++ AMQP implementation
+=============================
+
+= Project layout =
+
+For Build system design see comment at start of Makefile.
+
+Project contains:
+ * Client library (lib/libqpid_client): src/qpid/client
+ * Broker library (lib/libqpid_broker): src/qpid/broker
+ * Common classes
+ * src/qpid/concurrent: concurrecy
+ * src/qpid/framing: wire encoding/decoding
+ * src/qpid/io: reading/writing
+ * src/qpid/Exception.cpp, QpidError.cpp: Exception classes.
+ * Qpid Daemon (bin/qpidd): src/qpidd.cpp
+
+Unit tests in test/unit: each *Test.cpp builds a CppUnit plugin.
+
+Client tests in test/client: each *.cpp builds a test executable.
+
+Test utilities: test/include
+
+= Client Design =
+
+The client module is primarily concerned with presenting the
+functionality offered by AMQP to users through a simple API that
+nevertheless allows all the protocol functionality to be exploited.
+[Note: it is currently nothing like complete in this regard!]
+
+The code in the client module is concerned with the logic of the AMQP
+protocol and interacts with the lower level transport issues through
+the InputHandler and OutputHandler abstractions defined in
+common/framing. It uses these in conjunction with the Connector
+interface, defined in common/io, for establishing a connection to the
+broker and interacting with it through the sending and receiving of
+messages represented by AMQFrame (defined in common/framing).
+
+The Connector implementation is responsible for connection set up,
+threading strategy and getting data on and off the wire. It delegates
+to the framing module for encode/decode operations. The interface
+between the io and the framing modules is primarily through the Buffer
+and AMQFrame classes.
+
+A Buffer allows 'raw' data to be read or written in terms of the AMQP
+defined 'types' (octet, short, long, long long, short string, long
+string, field table etc.). AMQP is defined in terms frames with
+specific bodies and the frame (as well as these different bodies) are
+defined in terms of these 'types'. The AMQFrame class allows a frame
+to be decoded by reading from the supplied buffer, or it allows a
+particular frame to be constructed and then encoded by writing to the
+supplied buffer. The io layer can then access the raw data that
+'backs' the buffer to either out it on the wire or to populate it from
+the wire.
+
+One minor exception to this is the protocol initiation. AMQP defines
+a protocol 'header', that is not a frame, and is sent by a client to
+intiate a connection. The Connector allows (indeed requires) such a
+frame to be passed in to initialise the connection (the Acceptor, when
+defined, will allow an InitiationHandler to be set allowing the broker
+to hook into the connection initiation). In order to remove
+duplication, the ProtocolInitiation class and the AMQFrame class both
+implement a AMQDataBlock class that defines the encode and decode
+methods. This allows both types to be treated generically for the
+purposes of encoding. In decoding, the context determines which type
+is expected and should be used for decoding (this is only relevant to
+the broker).
+
+
+
+
+ --------api--------
+ Client Impl ...............uses.....
+input handler --> --------- --------- <-- output handler .
+ A | .
+ | | framing utils
+ | V .
+ ------------------- <-- connector .
+ IO Layer ................uses....
diff --git a/qpid/cpp/LICENSE b/qpid/cpp/LICENSE
new file mode 100644
index 0000000000..6b0b1270ff
--- /dev/null
+++ b/qpid/cpp/LICENSE
@@ -0,0 +1,203 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
+
diff --git a/qpid/cpp/Makefile.am b/qpid/cpp/Makefile.am
new file mode 100644
index 0000000000..42fc47ba5f
--- /dev/null
+++ b/qpid/cpp/Makefile.am
@@ -0,0 +1,43 @@
+AUTOMAKE_OPTIONS = 1.9.2 foreign
+ACLOCAL_AMFLAGS = -I m4
+
+SPEC=$(PACKAGE).spec
+
+EXTRA_DIST = \
+ LICENSE NOTICE README RELEASE_NOTES\
+ etc/qpidd etc/qpidd.conf \
+ $(SPEC) $(SPEC).in \
+ rpm/README.qpidd-devel \
+ xml/cluster.xml
+
+sysconf_DATA = etc/qpidd.conf
+
+SUBDIRS = src docs/api docs/man examples
+
+# Update libtool, if needed.
+libtool: $(LIBTOOL_DEPS)
+ $(SHELL) ./config.status --recheck
+
+#
+# Build RPMs from the distribution tarball.
+#
+RPMDIRS=rpm/BUILD rpm/RPMS rpm/SPECS rpm/SRPMS
+RPMMACROS=--define "_topdir @abs_builddir@/rpm" --define "_sourcedir @abs_builddir@"
+# Override this variable e.g. with -bs to produce srpm only
+RPMOPTS=-ba
+
+clean-local:
+ -rm -rf $(RPMDIRS)
+
+.PHONY: rpmbuild
+
+rpmbuild: $(SPEC) dist-gzip
+ mkdir -p $(RPMDIRS)
+ rpmbuild $(RPMMACROS) $(RPMOPTS) $(SPEC)
+if HAS_RPMLINT
+ rpmlint `find rpm -name '*.rpm'`
+else
+ @echo "WARNING: rpmlint not found, could not validate RPMs."
+endif
+
+
diff --git a/qpid/cpp/NOTICE b/qpid/cpp/NOTICE
new file mode 100644
index 0000000000..cae69a873a
--- /dev/null
+++ b/qpid/cpp/NOTICE
@@ -0,0 +1,25 @@
+=========================================================================
+== NOTICE file corresponding to the section 4 d of ==
+== the Apache License, Version 2.0, ==
+== in this case for the Apache Qpid distribution. ==
+=========================================================================
+
+This product includes software developed by the Apache Software Foundation
+(http://www.apache.org/).
+
+Please read the LICENSE file present in the root directory of this
+distribution.
+
+
+Aside from contributions to the Apache Qpid project, this software also
+includes (binary only):
+ - None at this time
+
+Project requires, not packaged:
+ * apr version 1.2.7 or later under the Apache Software License, Version 2.0,
+ and can be downloded from http://apr.apache.org
+
+ * boost version 1.33.1 or later under the Boost Software License, and
+ can be downloaded from http://www.boost.org
+ - Included in most OS platfroms by defualt.
+
diff --git a/qpid/cpp/README b/qpid/cpp/README
new file mode 100644
index 0000000000..7de7fd3f98
--- /dev/null
+++ b/qpid/cpp/README
@@ -0,0 +1,291 @@
+= Qpid C++ =
+
+Qpid C++ is a C++ implementation of the AMQP protcol described at
+ http://amqp.org/
+
+The Qpid project also provides Java, Ruby and Python implementations.
+
+NOTE: This release of Qpid C++ implements the AMQP 0-9 WIP.
+It will not inter-operate with AMQP 0-8 implementations.
+We will be moving to 0-10 as soon as it is available.
+
+For additional software or information on the Qpid project go to:
+ http://cwiki.apache.org/qpid/
+
+Available documentation:
+ qpidd(1) man page - how to run the broker daemon.
+ html/index.html - C++ client API.
+ NEWS - release notes.
+Note the daemon and client API can be installed separately.
+
+This README describes how to build the Qpid C++ broker and client, either
+from a checkout of the source or from a source distribution.
+
+== Prerequisites ==
+
+We prefer to avoid spending time accommodating older versions of these
+packages, so please make sure that you have the latest stable versions.
+Known version numbers for a succesfull build are given in brackets, take
+these as a recommended minimum version. Older unix versions, for example,
+Redhat Linux 3, will almost certainly require some packages to be upgraded.
+
+The following libraries and header files must be installed to build
+a source distribution:
+ * boost <http://www.boost.org> (1.33.1)
+ * e2fsprogs <http://e2fsprogs.sourceforge.net/> (1.39)
+ * pkgconfig <http://pkgconfig.freedesktop.org/wiki/> (0.21)
+
+Optional cluster functionality requires:
+ * openais <http://openais.org/> (0.80.3)
+
+Running qpid test suite requires:
+ * cppunit <http://cppunit.sourceforge.net> (1.11.4)
+
+Qpid has been built using the GNU C++ compiler:
+ * gcc <http://gcc.gnu.org/> (3.2.3)
+
+If you want to build directly from the SVN repository you will need
+all of the above plus:
+
+ * GNU make <http://www.gnu.org/software/make/> (3.8.0)
+ * autoconf <http://www.gnu.org/software/autoconf/> (2.61)
+ * automake <http://www.gnu.org/software/automake/> (1.9.6)
+ * help2man <http://www.gnu.org/software/help2man/> (1.36.4)
+ * libtool <http://www.gnu.org/software/libtool/> (1.5.22)
+ * doxygen <ftp://ftp.stack.nl/pub/users/dimitri/> (1.5.1)
+ * graphviz <http://www.graphviz.org/> (2.12)
+ * ruby 1.8 <http://www.ruby-lang.org> (1.8.4)
+
+=== Installing as root ===
+
+On linux most packages can be installed using your distribution's package
+management tool. For example on Fedora:
+ # yum install pkgconfig e2fsprogs boost-devel cppunit-devel openais-devel ruby
+ # yum install make gcc-c++ autoconf automake libtool doxygen help2man graphviz
+ # yum install e2fsprogs-devel
+
+Follow the manual installation instruction below for any packages not
+available through yum.
+
+=== Building and installing packages manually or as non-root user ===
+
+Required dependencies can be installed and built from source distributions.
+It is recommended that you create a directory to install them to, for example,
+~/qpid-tools. To build and install the dependency pakcages:
+
+ 1. Unzip and untar them and cd to the untared directory.
+ 2. do:
+ # ./configure --prefix=~/qpid-tools
+ # make install
+
+The exceptions are openais, boost, JDK 5.0.
+
+==== To build and install openais from source ====
+
+Unpack the source distribution and do:
+ # make
+ # sudo make install DESTDIR=
+ # sudo ldconfig
+
+This will install in the standard places (/usr/lib, /usr/include etc.)
+
+Edit /etc/ais/openais.conf and modify the "bindnetaddr" setting
+to your hosts IP address. Do not use 127.0.0.1.
+
+Make sure the UDP port set for mcastport in openais.conf (5405 by
+default) is not blocked by your firewall. Disable the firewall or
+configure it to allow this port for UDP.
+
+Finally start the ais daemon (must be done as root):
+ # sudo /sbin/aisexec
+
+Note that to run the AIS tests your primary group must be "ais". You
+can change your primary group with the usermod command or set it
+temporarily with the newgrp command.
+
+Troubleshooting tips:
+
+If aisexec goes into a loop printing "entering GATHER state", verify your firewall is allowing UDP traffic on the mcastport set in openais.conf.
+
+If aisexec reports "got nodejoin message 127.0.0.1" verify the
+bindnetaddr in openais.conf is an active local IP address. ifconfig
+will list local addresses.
+
+When aisexec is working correctly, the start-up log messages will end
+with "entering OPERATIONAL state." and "got nodejoin message <ip
+address>" where <ip address> is the local IP address specified for
+bindnetaddr in openais.conf.
+
+For further info on openais http://openais.org/
+
+==== To build the boost library ====
+
+ 1. Unpack boost-jam.
+ 2. Add bjam in the unpacked directory to your path.
+ 3. Unpack boost and cd to the boost untarred directory.
+ 4. do:
+
+ # bjam -sTOOLS=gcc --prefix=~/qpid-tools
+
+==== To install JDK 5.0 ====
+Download and run its install script, or whatever
+alternative instructions may be on the sun website.
+
+Ensure that all the build tools are available on your path, when they are
+manually installed to non-standard locations. For example:
+
+ # export PATH=~/qpid-tools/bin:$PATH
+
+Ensure that pkg-config is set up correctly. For example:
+
+ # export PKG_CONFIG_PATH=~/qpid-tools/lib/pkgconfig:/usr/local/pkgconfig
+ # export PKG_CONFIG=~/qpid-tools/bin/pkg-config
+
+Ensure that the boost libraries are made available on the gcc library path.
+For example:
+
+ # export CXXFLAGS=-I~/qpid-tools/include/boost-1_33_1
+
+Ensure that JDK 5.0 has its home location set up correctly and is added to
+the path. For example:
+
+ # export PATH=~/jdk1.5.0_11/bin:$PATH
+
+== Building from a source distribution. ==
+
+In the distribution directory
+
+Build and install with:
+
+ # ./configure --prefix=<install_location>
+ # make all
+ # make install
+
+To build and test everything:
+
+ # make
+ # make check
+
+This builds in the source tree. You can have multiple builds in the
+same working copy with different configuration. For example you can do
+the following to build twice, once for debug, the other with
+optimization:
+
+ # make distclean
+ # mkdir .build-dbg .build-opt
+ # (cd .build-opt ../configure --prefix=/tmp/x && make && make check)
+ # (cd .build-dbg ../configure CXXFLAGS=-g --prefix=/tmp/x \
+ && make && make check)
+
+
+== For Qpid developers: building a repository working copy ==
+
+=== Installing the latest autotools ===
+
+If you don't have sufficiently up-to-date autotools you can get the
+latest by running run the script qpid-autotools-install.
+
+1. Decide where you would like to install the tools. It should be in a
+ local directory so that you do not need root privileges. (Suggest
+ $HOME/qpid-tools.) Create an empty directory.
+2. Modify your environment variable PATH to ensure that the bin directory
+ within this directory comes first in the PATH string:
+ PATH=$HOME/qpid-tools/bin:$PATH
+3. Set PKG_CONFIG_PATH=$HOME/qpid-tools/lib/pkgconfig:/usr/lib/pkgconfig
+ (or if it already exists, make sure that the above path to your
+ qpid-tools directory is first).
+4. Run the install utility from the cpp directory:
+ ./qpid-autotools-install --prefix=$HOME/qpid-tools --skip-check
+ (Note that --prefix will only accept an absolute path, so don't use
+ ~/qpid-tools.) The utility will download, compile and install the
+ required tools into the qpid-tools directory (this may take a little
+ time). Watch for any notices about paths at the end of the install -
+ this means that your environment is not correct - see steps 2 and 3
+ above.
+ NOTE: If you omit the --skip-check option, the check of the build
+ can add up to an hour to what is normally a few minutes of install
+ time.
+5. Perform a check: from the command-line run "which automake" and
+ ensure that it finds the automake in your qpid-tools directory. If not,
+ check that the build completed normally and your environment.
+6. (Optional) If having the build artifacts lying around bothers you, delete
+ the (hidden) build directory cpp/.build-auto-tools.
+
+To see help, run ./qpid-autotools-install --help.
+
+=== Building a checkout ===
+To get the source code from the subversion repository (trunk) do:
+
+ # svn checkout https://svn.apache.org/repos/asf/incubator/qpid/trunk/ .
+
+To build a fresh checkout:
+
+Cd to qpid/cpp subdirectory. Before running make on a fresh checkout do:
+
+ # ./bootstrap
+
+This generates config, makefiles and the like - check the script for
+details. You only need to do this once, "make" will keep everything up
+to date thereafter (including re-generating configuration & Makefiles
+if the automake templates change etc.)
+
+If you are developing code yourself, or if you want to help
+us keep the code as tight and robust as possible, consider enabling
+the use of valgrind. If you configure like this:
+
+ # ./configure --enable-valgrind
+
+That will arrange (assuming you have valgrind installed) for "make check"
+to run tests via valgrind. That makes the tests run more slowly, but
+helps detect certain types of bugs, as well as memory leaks. If you run
+"make check" and valgrind detects a leak that is not listed as being
+"ignorable-for-now", the test script in question will fail. However,
+recording whether a leak is ignorable is not easy, when the stack
+signature, libraries, compiler, O/S, architecture, etc., may all vary,
+so if you see a new leak, try to figure out if it's one you can fix
+before adding it to the list.
+
+Now follow instruction for building from a source distribution.
+
+=== Portability ===
+
+All system calls are abstracted by classes under lib/common/sys. This
+provides an object-oriented C++ API and contains platform-specific
+code.
+
+These wrappers are mainly inline by-value classes so they impose no
+run-time penalty compared do direct system calls.
+
+Initially we will have a full linux implementation and a portable
+implementation sufficient for the client using the APR portability
+library. The implementations may change in future but the interface
+for qpid code outside the qpid/sys namespace should remain stable.
+
+=== Tests ===
+
+See src/tests/README for details.
+
+== Doxygen ==
+
+Doxygen generates documentation in several formats from source code
+using special comments. You can use javadoc style comments if you know
+javadoc, if you don't or want to know the fully story on doxygen
+markup see http://www.stack.nl/~dimitri/doxygen/
+
+Even even if the code is completely uncommented, doxygen generates
+UML-esque dependency diagrams that are ''extremely'' useful in navigating
+around the code, especially for newcomers.
+
+To try it out "make doxygen" then open doxygen/html/index.html
+This README describes how to build the Qpid C++ broker and client, either
+from a checkout of the source or from a source distribution.
+
+=== Troubleshooting ===
+
+When building, get the following on configure
+ configure: error: Package requirements (apr-1 >= 1.2.2) were not met:
+ No package 'apr-1' foun
+
+The following has not been set
+ export PKG_CONFIG_PATH=$HOME/qpid-tools/lib/pkgconfig:/usr/lib/pkgconfig
+
diff --git a/qpid/cpp/RELEASE_NOTES b/qpid/cpp/RELEASE_NOTES
new file mode 100644
index 0000000000..819539b1ec
--- /dev/null
+++ b/qpid/cpp/RELEASE_NOTES
@@ -0,0 +1,41 @@
+Apache Incubator Qpid C++ M2 Release Notes
+-------------------------------------------
+
+The Qpid M2 release contains support the for AMQP 0-8 specification.
+You can access the 0-8 specification using the following link.
+http://www.amqp.org/tikiwiki/tiki-index.php?page=Download
+
+For full details of Qpid capabilities, as they currently stand, see our
+detailed project documentation at:
+
+http://cwiki.apache.org/confluence/pages/viewpage.action?pageId=28284
+
+Please take time to go through the README file provided with the distro to get a good understanding about build system etc.
+
+
+Known Issues
+------------
+
+You can view the outstanding task list for Qpid by visiting our JIRA:
+http://issues.apache.org/jira/browse/QPID
+
+Bug QPID-437 c++ broker doesn't obey the mandatory flag
+
+
+M2 Tasks Completed
+-------------------
+
+Test QPID-412 Implement initial C++ interop tests
+Task QPID-124 Connect AMQP version from ProtocolInitiation object to all version-aware objects
+
+New Feature QPID-154 Logging/tracing for C++.
+New Feature QPID-98 implement durable exchanges
+New Feature QPID-41 Persistent storage for messages & durable queues
+
+Improvement QPID-450 C++ demos
+Improvement QPID-64 C++ cluster design.
+Improvement QPID-62 C++ event queue design.
+
+Bug QPID-481 c++ broker dosen't implement channel.flow
+Bug QPID-467 Complete Interop Testing
+Bug QPID-123 Sporadic failure on Python tests
diff --git a/qpid/cpp/bootstrap b/qpid/cpp/bootstrap
new file mode 100755
index 0000000000..c1fb753201
--- /dev/null
+++ b/qpid/cpp/bootstrap
@@ -0,0 +1,32 @@
+#!/bin/sh
+set -e
+aclocal -I m4
+autoheader
+libtoolize --automake
+
+# Generate (for automake) lots of repetitive parts of tests/Makefile.am.
+(cd src/tests && rm -f gen.mk
+ perl -ne '/^(include |if |else|endif)/ or print' Makefile.am \
+ | make -f - abs_srcdir=`dirname $(pwd)` gen.mk > /dev/null )
+
+# Create initial Makefile fragments that will force make to generate
+# the real ones.
+cat > src/rubygen.mk <<EOF
+\$(srcdir)/rubygen.mk: force
+ \$(rgen_cmd)
+EOF
+cat > src/managementgen.mk <<EOF
+\$(srcdir)/managementgen.mk: force
+ \$(mgen_cmd)
+EOF
+
+
+automake
+autoconf
+
+if [ "$1" = "-build" -o "$1" = "--build" ] ; then
+ shift
+ ./configure "$@"
+ make
+ make check
+fi
diff --git a/qpid/cpp/build-aux/compile b/qpid/cpp/build-aux/compile
new file mode 100755
index 0000000000..1b1d232169
--- /dev/null
+++ b/qpid/cpp/build-aux/compile
@@ -0,0 +1,142 @@
+#! /bin/sh
+# Wrapper for compilers which do not understand `-c -o'.
+
+scriptversion=2005-05-14.22
+
+# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc.
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+case $1 in
+ '')
+ echo "$0: No command. Try \`$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand `-c -o'.
+Remove `-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file `INSTALL'.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "compile $scriptversion"
+ exit $?
+ ;;
+esac
+
+ofile=
+cfile=
+eat=
+
+for arg
+do
+ if test -n "$eat"; then
+ eat=
+ else
+ case $1 in
+ -o)
+ # configure might choose to run compile as `compile cc -o foo foo.c'.
+ # So we strip `-o arg' only if arg is an object.
+ eat=1
+ case $2 in
+ *.o | *.obj)
+ ofile=$2
+ ;;
+ *)
+ set x "$@" -o "$2"
+ shift
+ ;;
+ esac
+ ;;
+ *.c)
+ cfile=$1
+ set x "$@" "$1"
+ shift
+ ;;
+ *)
+ set x "$@" "$1"
+ shift
+ ;;
+ esac
+ fi
+ shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+ # If no `-o' option was seen then we might have been invoked from a
+ # pattern rule where we don't need one. That is ok -- this is a
+ # normal compilation that the losing compiler can handle. If no
+ # `.c' file was seen then we are probably linking. That is also
+ # ok.
+ exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use `[/.-]' here to ensure that we don't use the same name
+# that we are using for the .o file. Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d
+while true; do
+ if mkdir "$lockdir" >/dev/null 2>&1; then
+ break
+ fi
+ sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+ mv "$cofile" "$ofile"
+elif test -f "${cofile}bj"; then
+ mv "${cofile}bj" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/qpid/cpp/build-aux/config.guess b/qpid/cpp/build-aux/config.guess
new file mode 100755
index 0000000000..c93201a4d2
--- /dev/null
+++ b/qpid/cpp/build-aux/config.guess
@@ -0,0 +1,1501 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
+# Inc.
+
+timestamp='2006-11-08'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > $dummy.c ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+ case "${UNAME_MACHINE_ARCH}" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ sh5el) machine=sh5le-unknown ;;
+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE_ARCH}" in
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep __ELF__ >/dev/null
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "${UNAME_VERSION}" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit ;;
+ *:OpenBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+ exit ;;
+ *:ekkoBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+ exit ;;
+ *:SolidBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+ exit ;;
+ macppc:MirBSD:*:*)
+ echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ *:MirBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ alpha:OSF1:*:*)
+ case $UNAME_RELEASE in
+ *4.0)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ ;;
+ *5.*)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE="alpha" ;;
+ "EV5 (21164)")
+ UNAME_MACHINE="alphaev5" ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE="alphaev56" ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE="alphapca56" ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE="alphapca57" ;;
+ "EV6 (21264)")
+ UNAME_MACHINE="alphaev6" ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE="alphaev67" ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE="alphaev69" ;;
+ "EV7 (21364)")
+ UNAME_MACHINE="alphaev7" ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE="alphaev79" ;;
+ esac
+ # A Pn.n version is a patched version.
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ exit ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-morphos
+ exit ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit ;;
+ *:z/VM:*:*)
+ echo s390-ibm-zvmoe
+ exit ;;
+ *:OS400:*:*)
+ echo powerpc-ibm-os400
+ exit ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit ;;
+ arm:riscos:*:*|arm:RISCOS:*:*)
+ echo arm-unknown-riscos
+ exit ;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit ;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7; exit ;;
+ esac ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ i86pc:SunOS:5.*:*)
+ echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten${UNAME_RELEASE}
+ exit ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c &&
+ dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`$dummy $dummyarg` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+ then
+ echo "$SYSTEM_NAME"
+ else
+ echo rs6000-ibm-aix3.2.5
+ fi
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit ;;
+ *:AIX:*:[45])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ ${HP_ARCH} = "hppa2.0w" ]
+ then
+ eval $set_cc_for_build
+
+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
+ # generating 64-bit code. GNU and HP use different nomenclature:
+ #
+ # $ CC_FOR_BUILD=cc ./config.guess
+ # => hppa2.0w-hp-hpux11.23
+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+ # => hppa64-hp-hpux11.23
+
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+ grep __LP64__ >/dev/null
+ then
+ HP_ARCH="hppa2.0w"
+ else
+ HP_ARCH="hppa64"
+ fi
+ fi
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo unknown-hitachi-hiuxwe2
+ exit ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ *:UNICOS/mp:*:*)
+ echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:FreeBSD:*:*)
+ case ${UNAME_MACHINE} in
+ pc98)
+ echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ amd64)
+ echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ *)
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ esac
+ exit ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit ;;
+ i*:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit ;;
+ i*:windows32*:*)
+ # uname -m includes "-pc" on this system.
+ echo ${UNAME_MACHINE}-mingw32
+ exit ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit ;;
+ x86:Interix*:[3456]*)
+ echo i586-pc-interix${UNAME_RELEASE}
+ exit ;;
+ EM64T:Interix*:[3456]* | authenticamd:Interix*:[3456]*)
+ echo x86_64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+ echo i${UNAME_MACHINE}-pc-mks
+ exit ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i586-pc-interix
+ exit ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ echo x86_64-unknown-cygwin
+ exit ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ *:GNU:*:*)
+ # the GNU system
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+ exit ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit ;;
+ arm*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ avr32*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ cris:Linux:*:*)
+ echo cris-axis-linux-gnu
+ exit ;;
+ crisv32:Linux:*:*)
+ echo crisv32-axis-linux-gnu
+ exit ;;
+ frv:Linux:*:*)
+ echo frv-unknown-linux-gnu
+ exit ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m32r*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ mips:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips
+ #undef mipsel
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mipsel
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+ /^CPU/{
+ s: ::g
+ p
+ }'`"
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips64
+ #undef mips64el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mips64el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips64
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+ /^CPU/{
+ s: ::g
+ p
+ }'`"
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ or32:Linux:*:*)
+ echo or32-unknown-linux-gnu
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-gnu
+ exit ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ exit ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ exit ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-gnu ;;
+ PA8*) echo hppa2.0-unknown-linux-gnu ;;
+ *) echo hppa-unknown-linux-gnu ;;
+ esac
+ exit ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-gnu
+ exit ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux
+ exit ;;
+ sh64*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ vax:Linux:*:*)
+ echo ${UNAME_MACHINE}-dec-linux-gnu
+ exit ;;
+ x86_64:Linux:*:*)
+ echo x86_64-unknown-linux-gnu
+ exit ;;
+ i*86:Linux:*:*)
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us. cd to the root directory to prevent
+ # problems with other programs or directories called `ld' in the path.
+ # Set LC_ALL=C to ensure ld outputs messages in English.
+ ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+ | sed -ne '/supported targets:/!d
+ s/[ ][ ]*/ /g
+ s/.*supported targets: *//
+ s/ .*//
+ p'`
+ case "$ld_supported_targets" in
+ elf32-i386)
+ TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+ ;;
+ a.out-i386-linux)
+ echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+ exit ;;
+ coff-i386)
+ echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+ exit ;;
+ "")
+ # Either a pre-BFD a.out linker (linux-gnuoldld) or
+ # one that does not give us useful --help.
+ echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+ exit ;;
+ esac
+ # Determine whether the default compiler is a.out or elf
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <features.h>
+ #ifdef __ELF__
+ # ifdef __GLIBC__
+ # if __GLIBC__ >= 2
+ LIBC=gnu
+ # else
+ LIBC=gnulibc1
+ # endif
+ # else
+ LIBC=gnulibc1
+ # endif
+ #else
+ #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+ LIBC=gnu
+ #else
+ LIBC=gnuaout
+ #endif
+ #endif
+ #ifdef __dietlibc__
+ LIBC=dietlibc
+ #endif
+EOF
+ eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+ /^LIBC/{
+ s: ::g
+ p
+ }'`"
+ test x"${LIBC}" != x && {
+ echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+ exit
+ }
+ test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
+ ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit ;;
+ i*86:syllable:*:*)
+ echo ${UNAME_MACHINE}-pc-syllable
+ exit ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i386.
+ echo i386-pc-msdosdjgpp
+ exit ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo ${UNAME_MACHINE}-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux${UNAME_RELEASE}
+ exit ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+ case $UNAME_PROCESSOR in
+ unknown) UNAME_PROCESSOR=powerpc ;;
+ esac
+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+ exit ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = "x86"; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+ exit ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit ;;
+ NSE-?:NONSTOP_KERNEL:*:*)
+ echo nse-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSR-?:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux${UNAME_RELEASE}
+ exit ;;
+ *:DragonFly:*:*)
+ echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case "${UNAME_MACHINE}" in
+ A*) echo alpha-dec-vms ; exit ;;
+ I*) echo ia64-dec-vms ; exit ;;
+ V*) echo vax-dec-vms ; exit ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ echo i386-pc-xenix
+ exit ;;
+ i*86:skyos:*:*)
+ echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+ exit ;;
+ i*86:rdos:*:*)
+ echo ${UNAME_MACHINE}-pc-rdos
+ exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+# include <sys/param.h>
+# if defined (BSD)
+# if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+# else
+# if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# endif
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# else
+ printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ c34*)
+ echo c34-convex-bsd
+ exit ;;
+ c38*)
+ echo c38-convex-bsd
+ exit ;;
+ c4*)
+ echo c4-convex-bsd
+ exit ;;
+ esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess
+and
+ http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/qpid/cpp/build-aux/config.rpath b/qpid/cpp/build-aux/config.rpath
new file mode 100755
index 0000000000..c492a93b66
--- /dev/null
+++ b/qpid/cpp/build-aux/config.rpath
@@ -0,0 +1,614 @@
+#! /bin/sh
+# Output a system dependent set of variables, describing how to set the
+# run time search path of shared libraries in an executable.
+#
+# Copyright 1996-2006 Free Software Foundation, Inc.
+# Taken from GNU libtool, 2001
+# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+#
+# The first argument passed to this file is the canonical host specification,
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld
+# should be set by the caller.
+#
+# The set of defined variables is at the end of this script.
+
+# Known limitations:
+# - On IRIX 6.5 with CC="cc", the run time search patch must not be longer
+# than 256 bytes, otherwise the compiler driver will dump core. The only
+# known workaround is to choose shorter directory names for the build
+# directory and/or the installation directory.
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+shrext=.so
+
+host="$1"
+host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+# Code taken from libtool.m4's _LT_CC_BASENAME.
+
+for cc_temp in $CC""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'`
+
+# Code taken from libtool.m4's AC_LIBTOOL_PROG_COMPILER_PIC.
+
+wl=
+if test "$GCC" = yes; then
+ wl='-Wl,'
+else
+ case "$host_os" in
+ aix*)
+ wl='-Wl,'
+ ;;
+ darwin*)
+ case $cc_basename in
+ xlc*)
+ wl='-Wl,'
+ ;;
+ esac
+ ;;
+ mingw* | pw32* | os2*)
+ ;;
+ hpux9* | hpux10* | hpux11*)
+ wl='-Wl,'
+ ;;
+ irix5* | irix6* | nonstopux*)
+ wl='-Wl,'
+ ;;
+ newsos6)
+ ;;
+ linux*)
+ case $cc_basename in
+ icc* | ecc*)
+ wl='-Wl,'
+ ;;
+ pgcc | pgf77 | pgf90)
+ wl='-Wl,'
+ ;;
+ ccc*)
+ wl='-Wl,'
+ ;;
+ como)
+ wl='-lopt='
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ wl='-Wl,'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+ osf3* | osf4* | osf5*)
+ wl='-Wl,'
+ ;;
+ sco3.2v5*)
+ ;;
+ solaris*)
+ wl='-Wl,'
+ ;;
+ sunos4*)
+ wl='-Qoption ld '
+ ;;
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ wl='-Wl,'
+ ;;
+ sysv4*MP*)
+ ;;
+ unicos*)
+ wl='-Wl,'
+ ;;
+ uts4*)
+ ;;
+ esac
+fi
+
+# Code taken from libtool.m4's AC_LIBTOOL_PROG_LD_SHLIBS.
+
+hardcode_libdir_flag_spec=
+hardcode_libdir_separator=
+hardcode_direct=no
+hardcode_minus_L=no
+
+case "$host_os" in
+ cygwin* | mingw* | pw32*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+esac
+
+ld_shlibs=yes
+if test "$with_gnu_ld" = yes; then
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ # Unlike libtool, we use -rpath here, not --rpath, since the documented
+ # option of GNU ld is called -rpath, not --rpath.
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ case "$host_os" in
+ aix3* | aix4* | aix5*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ ld_shlibs=no
+ fi
+ ;;
+ amigaos*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
+ # that the semantics of dynamic libraries on AmigaOS, at least up
+ # to version 4, is to share data among multiple programs linked
+ # with the same dynamic library. Since this doesn't match the
+ # behavior of shared libraries on other platforms, we cannot use
+ # them.
+ ld_shlibs=no
+ ;;
+ beos*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ :
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ cygwin* | mingw* | pw32*)
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ hardcode_libdir_flag_spec='-L$libdir'
+ if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+ :
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ interix3*)
+ hardcode_direct=no
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ ;;
+ linux*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ :
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ netbsd*)
+ ;;
+ solaris*)
+ if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
+ ld_shlibs=no
+ elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ :
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+ ld_shlibs=no
+ ;;
+ *)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+ ;;
+ sunos4*)
+ hardcode_direct=yes
+ ;;
+ *)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ :
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+ if test "$ld_shlibs" = no; then
+ hardcode_libdir_flag_spec=
+ fi
+else
+ case "$host_os" in
+ aix3*)
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ hardcode_minus_L=yes
+ if test "$GCC" = yes; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ hardcode_direct=unsupported
+ fi
+ ;;
+ aix4* | aix5*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ else
+ aix_use_runtimelinking=no
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[23]|aix4.[23].*|aix5*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ ;;
+ esac
+ fi
+ hardcode_direct=yes
+ hardcode_libdir_separator=':'
+ if test "$GCC" = yes; then
+ case $host_os in aix4.[012]|aix4.[012].*)
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" && \
+ strings "$collect2name" | grep resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ hardcode_direct=yes
+ else
+ # We have old collect2
+ hardcode_direct=unsupported
+ hardcode_minus_L=yes
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_libdir_separator=
+ fi
+ ;;
+ esac
+ fi
+ # Begin _LT_AC_SYS_LIBPATH_AIX.
+ echo 'int main () { return 0; }' > conftest.c
+ ${CC} ${LDFLAGS} conftest.c -o conftest
+ aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`
+ if test -z "$aix_libpath"; then
+ aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`
+ fi
+ if test -z "$aix_libpath"; then
+ aix_libpath="/usr/lib:/lib"
+ fi
+ rm -f conftest.c conftest
+ # End _LT_AC_SYS_LIBPATH_AIX.
+ if test "$aix_use_runtimelinking" = yes; then
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ else
+ if test "$host_cpu" = ia64; then
+ hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+ else
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ fi
+ fi
+ ;;
+ amigaos*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ # see comment about different semantics on the GNU ld section
+ ld_shlibs=no
+ ;;
+ bsdi[45]*)
+ ;;
+ cygwin* | mingw* | pw32*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ hardcode_libdir_flag_spec=' '
+ libext=lib
+ ;;
+ darwin* | rhapsody*)
+ hardcode_direct=no
+ if test "$GCC" = yes ; then
+ :
+ else
+ case $cc_basename in
+ xlc*)
+ ;;
+ *)
+ ld_shlibs=no
+ ;;
+ esac
+ fi
+ ;;
+ dgux*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ ;;
+ freebsd1*)
+ ld_shlibs=no
+ ;;
+ freebsd2.2*)
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ ;;
+ freebsd2*)
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ ;;
+ freebsd* | kfreebsd*-gnu | dragonfly*)
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ ;;
+ hpux9*)
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ ;;
+ hpux10*)
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ fi
+ ;;
+ hpux11*)
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ case $host_cpu in
+ hppa*64*|ia64*)
+ hardcode_direct=no
+ ;;
+ *)
+ hardcode_direct=yes
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ ;;
+ esac
+ fi
+ ;;
+ irix5* | irix6* | nonstopux*)
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ ;;
+ netbsd*)
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ ;;
+ newsos6)
+ hardcode_direct=yes
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ ;;
+ openbsd*)
+ hardcode_direct=yes
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ else
+ case "$host_os" in
+ openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+ hardcode_libdir_flag_spec='-R$libdir'
+ ;;
+ *)
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ ;;
+ os2*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ ;;
+ osf3*)
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ ;;
+ osf4* | osf5*)
+ if test "$GCC" = yes; then
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ else
+ # Both cc and cxx compiler support -rpath directly
+ hardcode_libdir_flag_spec='-rpath $libdir'
+ fi
+ hardcode_libdir_separator=:
+ ;;
+ solaris*)
+ hardcode_libdir_flag_spec='-R$libdir'
+ ;;
+ sunos4*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ ;;
+ sysv4)
+ case $host_vendor in
+ sni)
+ hardcode_direct=yes # is this really true???
+ ;;
+ siemens)
+ hardcode_direct=no
+ ;;
+ motorola)
+ hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ ;;
+ sysv4.3*)
+ ;;
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ ld_shlibs=yes
+ fi
+ ;;
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7*)
+ ;;
+ sysv5* | sco3.2v5* | sco5v6*)
+ hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
+ hardcode_libdir_separator=':'
+ ;;
+ uts4*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ ;;
+ *)
+ ld_shlibs=no
+ ;;
+ esac
+fi
+
+# Check dynamic linker characteristics
+# Code taken from libtool.m4's AC_LIBTOOL_SYS_DYNAMIC_LINKER.
+libname_spec='lib$name'
+case "$host_os" in
+ aix3*)
+ ;;
+ aix4* | aix5*)
+ ;;
+ amigaos*)
+ ;;
+ beos*)
+ ;;
+ bsdi[45]*)
+ ;;
+ cygwin* | mingw* | pw32*)
+ shrext=.dll
+ ;;
+ darwin* | rhapsody*)
+ shrext=.dylib
+ ;;
+ dgux*)
+ ;;
+ freebsd1*)
+ ;;
+ kfreebsd*-gnu)
+ ;;
+ freebsd* | dragonfly*)
+ ;;
+ gnu*)
+ ;;
+ hpux9* | hpux10* | hpux11*)
+ case $host_cpu in
+ ia64*)
+ shrext=.so
+ ;;
+ hppa*64*)
+ shrext=.sl
+ ;;
+ *)
+ shrext=.sl
+ ;;
+ esac
+ ;;
+ interix3*)
+ ;;
+ irix5* | irix6* | nonstopux*)
+ case "$host_os" in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;;
+ *) libsuff= shlibsuff= ;;
+ esac
+ ;;
+ esac
+ ;;
+ linux*oldld* | linux*aout* | linux*coff*)
+ ;;
+ linux*)
+ ;;
+ knetbsd*-gnu)
+ ;;
+ netbsd*)
+ ;;
+ newsos6)
+ ;;
+ nto-qnx*)
+ ;;
+ openbsd*)
+ ;;
+ os2*)
+ libname_spec='$name'
+ shrext=.dll
+ ;;
+ osf3* | osf4* | osf5*)
+ ;;
+ solaris*)
+ ;;
+ sunos4*)
+ ;;
+ sysv4 | sysv4.3*)
+ ;;
+ sysv4*MP*)
+ ;;
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ ;;
+ uts4*)
+ ;;
+esac
+
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"`
+shlibext=`echo "$shrext" | sed -e 's,^\.,,'`
+escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
+
+LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <<EOF
+
+# How to pass a linker flag through the compiler.
+wl="$escaped_wl"
+
+# Static library suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally "so").
+shlibext="$shlibext"
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec="$escaped_hardcode_libdir_flag_spec"
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator="$hardcode_libdir_separator"
+
+# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct="$hardcode_direct"
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L="$hardcode_minus_L"
+
+EOF
diff --git a/qpid/cpp/build-aux/config.sub b/qpid/cpp/build-aux/config.sub
new file mode 100755
index 0000000000..7ccee73057
--- /dev/null
+++ b/qpid/cpp/build-aux/config.sub
@@ -0,0 +1,1619 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
+# Inc.
+
+timestamp='2006-11-07'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine. It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit ;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
+ uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+ storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis | -knuth | -cray)
+ os=
+ basic_machine=$1
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco6)
+ os=-sco5v6
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5v6*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | am33_2.0 \
+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+ | bfin \
+ | c4x | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | fr30 | frv \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | i370 | i860 | i960 | ia64 \
+ | ip2k | iq2000 \
+ | m32c | m32r | m32rle | m68000 | m68k | m88k \
+ | maxq | mb | microblaze | mcore \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64vr | mips64vrel \
+ | mips64orion | mips64orionel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | mt \
+ | msp430 \
+ | nios | nios2 \
+ | ns16k | ns32k \
+ | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+ | pyramid \
+ | score \
+ | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+ | spu | strongarm \
+ | tahoe | thumb | tic4x | tic80 | tron \
+ | v850 | v850e \
+ | we32k \
+ | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
+ | z8k)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12)
+ # Motorola 68HC11/12.
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+ ms1)
+ basic_machine=mt-unknown
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* | avr32-* \
+ | bfin-* | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+ | clipper-* | craynv-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | ip2k-* | iq2000-* \
+ | m32c-* | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mips64vr5900-* | mips64vr5900el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64r2-* | mipsisa64r2el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipstx39-* | mipstx39el-* \
+ | mmix-* \
+ | mt-* \
+ | msp430-* \
+ | nios-* | nios2-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+ | pyramid-* \
+ | romp-* | rs6000-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+ | sparclite-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
+ | tahoe-* | thumb-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tron-* \
+ | v850-* | v850e-* | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+ | xstormy16-* | xtensa-* \
+ | ymp-* \
+ | z8k-*)
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ abacus)
+ basic_machine=abacus-unknown
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amd64-*)
+ basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ craynv)
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+ cr16c)
+ basic_machine=cr16c-unknown
+ os=-elf
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ crisv32 | crisv32-* | etraxfs*)
+ basic_machine=crisv32-axis
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ crx)
+ basic_machine=crx-unknown
+ os=-elf
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ os=-msdosdjgpp
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ mingw32)
+ basic_machine=i386-pc
+ os=-mingw32
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ ms1-*)
+ basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ openrisc | openrisc-*)
+ basic_machine=or32-unknown
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ os=-os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pc98)
+ basic_machine=i386-pc
+ ;;
+ pc98-*)
+ basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
+ basic_machine=i686-pc
+ ;;
+ pentium4)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc) basic_machine=powerpc-unknown
+ ;;
+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rdos)
+ basic_machine=i386-pc
+ os=-rdos
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sde)
+ basic_machine=mipsisa32-sde
+ os=-elf
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sh5el)
+ basic_machine=sh5le-unknown
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparclite-wrs | simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ tic54x | c54x*)
+ basic_machine=tic54x-unknown
+ os=-coff
+ ;;
+ tic55x | c55x*)
+ basic_machine=tic55x-unknown
+ os=-coff
+ ;;
+ tic6x | c6x*)
+ basic_machine=tic6x-unknown
+ os=-coff
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ os=-tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ mmix)
+ basic_machine=mmix-knuth
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+ | -openbsd* | -solidbsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* \
+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
+ | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+ | -skyos* | -haiku* | -rdos* | -toppers*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux-dietlibc)
+ os=-linux-dietlibc
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -os400*)
+ os=-os400
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -syllable*)
+ os=-syllable
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -tpf*)
+ os=-tpf
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -aros*)
+ os=-aros
+ ;;
+ -kaos*)
+ os=-kaos
+ ;;
+ -zvmoe)
+ os=-zvmoe
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ score-*)
+ os=-elf
+ ;;
+ spu-*)
+ os=-elf
+ ;;
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-haiku)
+ os=-haiku
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-knuth)
+ os=-mmixware
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -os400*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -tpf*)
+ vendor=ibm
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/qpid/cpp/build-aux/depcomp b/qpid/cpp/build-aux/depcomp
new file mode 100755
index 0000000000..ca5ea4e1ef
--- /dev/null
+++ b/qpid/cpp/build-aux/depcomp
@@ -0,0 +1,584 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2006-10-15.18
+
+# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006 Free Software
+# Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
+
+case $1 in
+ '')
+ echo "$0: No command. Try \`$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+ depmode Dependency tracking mode.
+ source Source file read by `PROGRAMS ARGS'.
+ object Object file output by `PROGRAMS ARGS'.
+ DEPDIR directory where to store dependencies.
+ depfile Dependency file to output.
+ tmpdepfile Temporary file to use when outputing dependencies.
+ libtool Whether libtool is used (yes/no).
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "depcomp $scriptversion"
+ exit $?
+ ;;
+esac
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+ echo "depcomp: Variables source, object and depmode must be set" 1>&2
+ exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+ sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Some modes work just like other modes, but use different flags. We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write. Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+ # HP compiler uses -M and no extra arg.
+ gccflag=-M
+ depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+ # This is just like dashmstdout with a different argument.
+ dashmflag=-xM
+ depmode=dashmstdout
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want. Yay! Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff. Hmm.
+## Unfortunately, FreeBSD c89 acceptance of flags depends upon
+## the command line argument order; so add the flags where they
+## appear in depend2.am. Note that the slowdown incurred here
+## affects only configure: in makefiles, %FASTDEP% shortcuts this.
+ for arg
+ do
+ case $arg in
+ -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
+ *) set fnord "$@" "$arg" ;;
+ esac
+ shift # fnord
+ shift # $arg
+ done
+ "$@"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ mv "$tmpdepfile" "$depfile"
+ ;;
+
+gcc)
+## There are various ways to get dependency output from gcc. Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+## up in a subdir. Having to rename by hand is ugly.
+## (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+## -MM, not -M (despite what the docs say).
+## - Using -M directly means running the compiler twice (even worse
+## than renaming).
+ if test -z "$gccflag"; then
+ gccflag=-MD,
+ fi
+ "$@" -Wp,"$gccflag$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
+## The second -e expression handles DOS-style file names with drive letters.
+ sed -e 's/^[^:]*: / /' \
+ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the `deleted header file' problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header). We avoid this by adding
+## dummy dependencies for each header file. Too bad gcc doesn't do
+## this for us directly.
+ tr ' ' '
+' < "$tmpdepfile" |
+## Some versions of gcc put a space before the `:'. On the theory
+## that the space means something, we add a space to the output as
+## well.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+sgi)
+ if test "$libtool" = yes; then
+ "$@" "-Wp,-MDupdate,$tmpdepfile"
+ else
+ "$@" -MDupdate "$tmpdepfile"
+ fi
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+
+ if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
+ echo "$object : \\" > "$depfile"
+
+ # Clip off the initial element (the dependent). Don't try to be
+ # clever and replace this with sed code, as IRIX sed won't handle
+ # lines with more than a fixed number of characters (4096 in
+ # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
+ # the IRIX cc adds comments like `#:fec' to the end of the
+ # dependency line.
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
+ tr '
+' ' ' >> $depfile
+ echo >> $depfile
+
+ # The second pass generates a dummy entry for each header file.
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+ >> $depfile
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+aix)
+ # The C for AIX Compiler uses -M and outputs the dependencies
+ # in a .u file. In older versions, this file always lives in the
+ # current directory. Also, the AIX compiler puts `$object:' at the
+ # start of each line; $object doesn't have directory information.
+ # Version 6 uses the directory in both cases.
+ stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'`
+ tmpdepfile="$stripped.u"
+ if test "$libtool" = yes; then
+ "$@" -Wc,-M
+ else
+ "$@" -M
+ fi
+ stat=$?
+
+ if test -f "$tmpdepfile"; then :
+ else
+ stripped=`echo "$stripped" | sed 's,^.*/,,'`
+ tmpdepfile="$stripped.u"
+ fi
+
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+
+ if test -f "$tmpdepfile"; then
+ outname="$stripped.o"
+ # Each line is of the form `foo.o: dependent.h'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile"
+ sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile"
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+icc)
+ # Intel's C compiler understands `-MD -MF file'. However on
+ # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
+ # ICC 7.0 will fill foo.d with something like
+ # foo.o: sub/foo.c
+ # foo.o: sub/foo.h
+ # which is wrong. We want:
+ # sub/foo.o: sub/foo.c
+ # sub/foo.o: sub/foo.h
+ # sub/foo.c:
+ # sub/foo.h:
+ # ICC 7.1 will output
+ # foo.o: sub/foo.c sub/foo.h
+ # and will wrap long lines using \ :
+ # foo.o: sub/foo.c ... \
+ # sub/foo.h ... \
+ # ...
+
+ "$@" -MD -MF "$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ # Each line is of the form `foo.o: dependent.h',
+ # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process this invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
+ sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp2)
+ # The "hp" stanza above does not work with aCC (C++) and HP's ia64
+ # compilers, which have integrated preprocessors. The correct option
+ # to use with these is +Maked; it writes dependencies to a file named
+ # 'foo.d', which lands next to the object file, wherever that
+ # happens to be.
+ # Much of this is similar to the tru64 case; see comments there.
+ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+ test "x$dir" = "x$object" && dir=
+ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+ if test "$libtool" = yes; then
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir.libs/$base.d
+ "$@" -Wc,+Maked
+ else
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir$base.d
+ "$@" +Maked
+ fi
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile1" "$tmpdepfile2"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile"
+ # Add `dependent.h:' lines.
+ sed -ne '2,${; s/^ *//; s/ \\*$//; s/$/:/; p;}' "$tmpdepfile" >> "$depfile"
+ else
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile" "$tmpdepfile2"
+ ;;
+
+tru64)
+ # The Tru64 compiler uses -MD to generate dependencies as a side
+ # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
+ # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+ # dependencies in `foo.d' instead, so we check for that too.
+ # Subdirectories are respected.
+ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+ test "x$dir" = "x$object" && dir=
+ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+
+ if test "$libtool" = yes; then
+ # With Tru64 cc, shared objects can also be used to make a
+ # static library. This mechanism is used in libtool 1.4 series to
+ # handle both shared and static libraries in a single compilation.
+ # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d.
+ #
+ # With libtool 1.5 this exception was removed, and libtool now
+ # generates 2 separate objects for the 2 libraries. These two
+ # compilations output dependencies in $dir.libs/$base.o.d and
+ # in $dir$base.o.d. We have to check for both files, because
+ # one of the two compilations can be disabled. We should prefer
+ # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+ # automatically cleaned when .libs/ is deleted, while ignoring
+ # the former would cause a distcleancheck panic.
+ tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4
+ tmpdepfile2=$dir$base.o.d # libtool 1.5
+ tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5
+ tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504
+ "$@" -Wc,-MD
+ else
+ tmpdepfile1=$dir$base.o.d
+ tmpdepfile2=$dir$base.d
+ tmpdepfile3=$dir$base.d
+ tmpdepfile4=$dir$base.d
+ "$@" -MD
+ fi
+
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+ # That's a tab and a space in the [].
+ sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+ else
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+#nosideeffect)
+ # This comment above is used by automake to tell side-effect
+ # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout, regardless of -o.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove `-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ test -z "$dashmflag" && dashmflag=-M
+ # Require at least two characters before searching for `:'
+ # in the target name. This is to cope with DOS-style filenames:
+ # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
+ "$@" $dashmflag |
+ sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ tr ' ' '
+' < "$tmpdepfile" | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+dashXmstdout)
+ # This case only exists to satisfy depend.m4. It is never actually
+ # run, as this mode is specially recognized in the preamble.
+ exit 1
+ ;;
+
+makedepend)
+ "$@" || exit $?
+ # Remove any Libtool call
+ if test "$libtool" = yes; then
+ while test $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+ # X makedepend
+ shift
+ cleared=no
+ for arg in "$@"; do
+ case $cleared in
+ no)
+ set ""; shift
+ cleared=yes ;;
+ esac
+ case "$arg" in
+ -D*|-I*)
+ set fnord "$@" "$arg"; shift ;;
+ # Strip any option that makedepend may not understand. Remove
+ # the object too, otherwise makedepend will parse it as a source file.
+ -*|$object)
+ ;;
+ *)
+ set fnord "$@" "$arg"; shift ;;
+ esac
+ done
+ obj_suffix="`echo $object | sed 's/^.*\././'`"
+ touch "$tmpdepfile"
+ ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ sed '1,2d' "$tmpdepfile" | tr ' ' '
+' | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile" "$tmpdepfile".bak
+ ;;
+
+cpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove `-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ "$@" -E |
+ sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
+ sed '$ s: \\$::' > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ cat < "$tmpdepfile" >> "$depfile"
+ sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvisualcpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout, regardless of -o,
+ # because we must use -o when running libtool.
+ "$@" || exit $?
+ IFS=" "
+ for arg
+ do
+ case "$arg" in
+ "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+ set fnord "$@"
+ shift
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift
+ shift
+ ;;
+ esac
+ done
+ "$@" -E |
+ sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
+ echo " " >> "$depfile"
+ . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+none)
+ exec "$@"
+ ;;
+
+*)
+ echo "Unknown depmode $depmode" 1>&2
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/qpid/cpp/build-aux/install-sh b/qpid/cpp/build-aux/install-sh
new file mode 100755
index 0000000000..4fbbae7b7f
--- /dev/null
+++ b/qpid/cpp/build-aux/install-sh
@@ -0,0 +1,507 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2006-10-14.15
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+nl='
+'
+IFS=" "" $nl"
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+if test -z "$doit"; then
+ doit_exec=exec
+else
+ doit_exec=$doit
+fi
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+posix_glob=
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+chmodcmd=$chmodprog
+chowncmd=
+chgrpcmd=
+stripcmd=
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=
+dst=
+dir_arg=
+dstarg=
+no_target_directory=
+
+usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+ or: $0 [OPTION]... SRCFILES... DIRECTORY
+ or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+ or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+-c (ignored)
+-d create directories instead of installing files.
+-g GROUP $chgrpprog installed files to GROUP.
+-m MODE $chmodprog installed files to MODE.
+-o USER $chownprog installed files to USER.
+-s $stripprog installed files.
+-t DIRECTORY install into DIRECTORY.
+-T report an error if DSTFILE is a directory.
+--help display this help and exit.
+--version display version info and exit.
+
+Environment variables override the default commands:
+ CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
+"
+
+while test $# -ne 0; do
+ case $1 in
+ -c) shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ --help) echo "$usage"; exit $?;;
+
+ -m) mode=$2
+ shift
+ shift
+ case $mode in
+ *' '* | *' '* | *'
+'* | *'*'* | *'?'* | *'['*)
+ echo "$0: invalid mode: $mode" >&2
+ exit 1;;
+ esac
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd=$stripprog
+ shift
+ continue;;
+
+ -t) dstarg=$2
+ shift
+ shift
+ continue;;
+
+ -T) no_target_directory=true
+ shift
+ continue;;
+
+ --version) echo "$0 $scriptversion"; exit $?;;
+
+ --) shift
+ break;;
+
+ -*) echo "$0: invalid option: $1" >&2
+ exit 1;;
+
+ *) break;;
+ esac
+done
+
+if test $# -ne 0 && test -z "$dir_arg$dstarg"; then
+ # When -d is used, all remaining arguments are directories to create.
+ # When -t is used, the destination is already specified.
+ # Otherwise, the last argument is the destination. Remove it from $@.
+ for arg
+ do
+ if test -n "$dstarg"; then
+ # $@ is not empty: it contains at least $arg.
+ set fnord "$@" "$dstarg"
+ shift # fnord
+ fi
+ shift # arg
+ dstarg=$arg
+ done
+fi
+
+if test $# -eq 0; then
+ if test -z "$dir_arg"; then
+ echo "$0: no input file specified." >&2
+ exit 1
+ fi
+ # It's OK to call `install-sh -d' without argument.
+ # This can happen when creating conditional directories.
+ exit 0
+fi
+
+if test -z "$dir_arg"; then
+ trap '(exit $?); exit' 1 2 13 15
+
+ # Set umask so as not to create temps with too-generous modes.
+ # However, 'strip' requires both read and write access to temps.
+ case $mode in
+ # Optimize common cases.
+ *644) cp_umask=133;;
+ *755) cp_umask=22;;
+
+ *[0-7])
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw='% 200'
+ fi
+ cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+ *)
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw=,u+rw
+ fi
+ cp_umask=$mode$u_plus_rw;;
+ esac
+fi
+
+for src
+do
+ # Protect names starting with `-'.
+ case $src in
+ -*) src=./$src ;;
+ esac
+
+ if test -n "$dir_arg"; then
+ dst=$src
+ dstdir=$dst
+ test -d "$dstdir"
+ dstdir_status=$?
+ else
+
+ # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+ # might cause directories to be created, which would be especially bad
+ # if $src (and thus $dsttmp) contains '*'.
+ if test ! -f "$src" && test ! -d "$src"; then
+ echo "$0: $src does not exist." >&2
+ exit 1
+ fi
+
+ if test -z "$dstarg"; then
+ echo "$0: no destination specified." >&2
+ exit 1
+ fi
+
+ dst=$dstarg
+ # Protect names starting with `-'.
+ case $dst in
+ -*) dst=./$dst ;;
+ esac
+
+ # If destination is a directory, append the input filename; won't work
+ # if double slashes aren't ignored.
+ if test -d "$dst"; then
+ if test -n "$no_target_directory"; then
+ echo "$0: $dstarg: Is a directory" >&2
+ exit 1
+ fi
+ dstdir=$dst
+ dst=$dstdir/`basename "$src"`
+ dstdir_status=0
+ else
+ # Prefer dirname, but fall back on a substitute if dirname fails.
+ dstdir=`
+ (dirname "$dst") 2>/dev/null ||
+ expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$dst" : 'X\(//\)[^/]' \| \
+ X"$dst" : 'X\(//\)$' \| \
+ X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
+ echo X"$dst" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'
+ `
+
+ test -d "$dstdir"
+ dstdir_status=$?
+ fi
+ fi
+
+ obsolete_mkdir_used=false
+
+ if test $dstdir_status != 0; then
+ case $posix_mkdir in
+ '')
+ # Create intermediate dirs using mode 755 as modified by the umask.
+ # This is like FreeBSD 'install' as of 1997-10-28.
+ umask=`umask`
+ case $stripcmd.$umask in
+ # Optimize common cases.
+ *[2367][2367]) mkdir_umask=$umask;;
+ .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+ *[0-7])
+ mkdir_umask=`expr $umask + 22 \
+ - $umask % 100 % 40 + $umask % 20 \
+ - $umask % 10 % 4 + $umask % 2
+ `;;
+ *) mkdir_umask=$umask,go-w;;
+ esac
+
+ # With -d, create the new directory with the user-specified mode.
+ # Otherwise, rely on $mkdir_umask.
+ if test -n "$dir_arg"; then
+ mkdir_mode=-m$mode
+ else
+ mkdir_mode=
+ fi
+
+ posix_mkdir=false
+ case $umask in
+ *[123567][0-7][0-7])
+ # POSIX mkdir -p sets u+wx bits regardless of umask, which
+ # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+ ;;
+ *)
+ tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+ if (umask $mkdir_umask &&
+ exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
+ then
+ if test -z "$dir_arg" || {
+ # Check for POSIX incompatibilities with -m.
+ # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+ # other-writeable bit of parent directory when it shouldn't.
+ # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+ ls_ld_tmpdir=`ls -ld "$tmpdir"`
+ case $ls_ld_tmpdir in
+ d????-?r-*) different_mode=700;;
+ d????-?--*) different_mode=755;;
+ *) false;;
+ esac &&
+ $mkdirprog -m$different_mode -p -- "$tmpdir" && {
+ ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
+ test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+ }
+ }
+ then posix_mkdir=:
+ fi
+ rmdir "$tmpdir/d" "$tmpdir"
+ else
+ # Remove any dirs left behind by ancient mkdir implementations.
+ rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
+ fi
+ trap '' 0;;
+ esac;;
+ esac
+
+ if
+ $posix_mkdir && (
+ umask $mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+ )
+ then :
+ else
+
+ # The umask is ridiculous, or mkdir does not conform to POSIX,
+ # or it failed possibly due to a race condition. Create the
+ # directory the slow way, step by step, checking for races as we go.
+
+ case $dstdir in
+ /*) prefix=/ ;;
+ -*) prefix=./ ;;
+ *) prefix= ;;
+ esac
+
+ case $posix_glob in
+ '')
+ if (set -f) 2>/dev/null; then
+ posix_glob=true
+ else
+ posix_glob=false
+ fi ;;
+ esac
+
+ oIFS=$IFS
+ IFS=/
+ $posix_glob && set -f
+ set fnord $dstdir
+ shift
+ $posix_glob && set +f
+ IFS=$oIFS
+
+ prefixes=
+
+ for d
+ do
+ test -z "$d" && continue
+
+ prefix=$prefix$d
+ if test -d "$prefix"; then
+ prefixes=
+ else
+ if $posix_mkdir; then
+ (umask=$mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+ # Don't fail if two instances are running concurrently.
+ test -d "$prefix" || exit 1
+ else
+ case $prefix in
+ *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) qprefix=$prefix;;
+ esac
+ prefixes="$prefixes '$qprefix'"
+ fi
+ fi
+ prefix=$prefix/
+ done
+
+ if test -n "$prefixes"; then
+ # Don't fail if two instances are running concurrently.
+ (umask $mkdir_umask &&
+ eval "\$doit_exec \$mkdirprog $prefixes") ||
+ test -d "$dstdir" || exit 1
+ obsolete_mkdir_used=true
+ fi
+ fi
+ fi
+
+ if test -n "$dir_arg"; then
+ { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+ { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+ else
+
+ # Make a couple of temp file names in the proper directory.
+ dsttmp=$dstdir/_inst.$$_
+ rmtmp=$dstdir/_rm.$$_
+
+ # Trap to clean up those temp files at exit.
+ trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+ # Copy the file name to the temp name.
+ (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+ # and set any options; do chmod last to preserve setuid bits.
+ #
+ # If any of these fail, we abort the whole thing. If we want to
+ # ignore errors from any of these, just make sure not to ignore
+ # errors from the above "$doit $cpprog $src $dsttmp" command.
+ #
+ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
+ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
+ && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
+ && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+ # Now rename the file to the real destination.
+ { $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null \
+ || {
+ # The rename failed, perhaps because mv can't rename something else
+ # to itself, or perhaps because mv is so ancient that it does not
+ # support -f.
+
+ # Now remove or move aside any old file at destination location.
+ # We try this two ways since rm can't unlink itself on some
+ # systems and the destination file might be busy for other
+ # reasons. In this case, the final cleanup might fail but the new
+ # file should still install successfully.
+ {
+ if test -f "$dst"; then
+ $doit $rmcmd -f "$dst" 2>/dev/null \
+ || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null \
+ && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }; }\
+ || {
+ echo "$0: cannot unlink or rename $dst" >&2
+ (exit 1); exit 1
+ }
+ else
+ :
+ fi
+ } &&
+
+ # Now rename the file to the real destination.
+ $doit $mvcmd "$dsttmp" "$dst"
+ }
+ } || exit 1
+
+ trap '' 0
+ fi
+done
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/qpid/cpp/build-aux/ltmain.sh b/qpid/cpp/build-aux/ltmain.sh
new file mode 100755
index 0000000000..c715b59412
--- /dev/null
+++ b/qpid/cpp/build-aux/ltmain.sh
@@ -0,0 +1,6871 @@
+# ltmain.sh - Provide generalized library-building support services.
+# NOTE: Changing this file will not affect anything until you rerun configure.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+basename="s,^.*/,,g"
+
+# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
+# is ksh but when the shell is invoked as "sh" and the current value of
+# the _XPG environment variable is not equal to 1 (one), the special
+# positional parameter $0, within a function call, is the name of the
+# function.
+progpath="$0"
+
+# The name of this program:
+progname=`echo "$progpath" | $SED $basename`
+modename="$progname"
+
+# Global variables:
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+
+PROGRAM=ltmain.sh
+PACKAGE=libtool
+VERSION="1.5.22 Debian 1.5.22-4"
+TIMESTAMP=" (1.1220.2.365 2005/12/18 22:14:06)"
+
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes.
+if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+
+# Check that we have a working $echo.
+if test "X$1" = X--no-reexec; then
+ # Discard the --no-reexec flag, and continue.
+ shift
+elif test "X$1" = X--fallback-echo; then
+ # Avoid inline document here, it may be left over
+ :
+elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then
+ # Yippee, $echo works!
+ :
+else
+ # Restart under the correct shell, and then maybe $echo will work.
+ exec $SHELL "$progpath" --no-reexec ${1+"$@"}
+fi
+
+if test "X$1" = X--fallback-echo; then
+ # used as fallback echo
+ shift
+ cat <<EOF
+$*
+EOF
+ exit $EXIT_SUCCESS
+fi
+
+default_mode=
+help="Try \`$progname --help' for more information."
+magic="%%%MAGIC variable%%%"
+mkdir="mkdir"
+mv="mv -f"
+rm="rm -f"
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed="${SED}"' -e 1s/^X//'
+sed_quote_subst='s/\([\\`\\"$\\\\]\)/\\\1/g'
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+ # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+ SP2NL='tr \040 \012'
+ NL2SP='tr \015\012 \040\040'
+ ;;
+ *) # EBCDIC based system
+ SP2NL='tr \100 \n'
+ NL2SP='tr \r\n \100\100'
+ ;;
+esac
+
+# NLS nuisances.
+# Only set LANG and LC_ALL to C if already set.
+# These must not be set unconditionally because not all systems understand
+# e.g. LANG=C (notably SCO).
+# We save the old values to restore during execute mode.
+if test "${LC_ALL+set}" = set; then
+ save_LC_ALL="$LC_ALL"; LC_ALL=C; export LC_ALL
+fi
+if test "${LANG+set}" = set; then
+ save_LANG="$LANG"; LANG=C; export LANG
+fi
+
+# Make sure IFS has a sensible default
+lt_nl='
+'
+IFS=" $lt_nl"
+
+if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
+ $echo "$modename: not configured to build any kind of library" 1>&2
+ $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
+ exit $EXIT_FAILURE
+fi
+
+# Global variables.
+mode=$default_mode
+nonopt=
+prev=
+prevopt=
+run=
+show="$echo"
+show_help=
+execute_dlfiles=
+duplicate_deps=no
+preserve_args=
+lo2o="s/\\.lo\$/.${objext}/"
+o2lo="s/\\.${objext}\$/.lo/"
+
+#####################################
+# Shell function definitions:
+# This seems to be the best place for them
+
+# func_mktempdir [string]
+# Make a temporary directory that won't clash with other running
+# libtool processes, and avoids race conditions if possible. If
+# given, STRING is the basename for that directory.
+func_mktempdir ()
+{
+ my_template="${TMPDIR-/tmp}/${1-$progname}"
+
+ if test "$run" = ":"; then
+ # Return a directory name, but don't create it in dry-run mode
+ my_tmpdir="${my_template}-$$"
+ else
+
+ # If mktemp works, use that first and foremost
+ my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null`
+
+ if test ! -d "$my_tmpdir"; then
+ # Failing that, at least try and use $RANDOM to avoid a race
+ my_tmpdir="${my_template}-${RANDOM-0}$$"
+
+ save_mktempdir_umask=`umask`
+ umask 0077
+ $mkdir "$my_tmpdir"
+ umask $save_mktempdir_umask
+ fi
+
+ # If we're not in dry-run mode, bomb out on failure
+ test -d "$my_tmpdir" || {
+ $echo "cannot create temporary directory \`$my_tmpdir'" 1>&2
+ exit $EXIT_FAILURE
+ }
+ fi
+
+ $echo "X$my_tmpdir" | $Xsed
+}
+
+
+# func_win32_libid arg
+# return the library type of file 'arg'
+#
+# Need a lot of goo to handle *both* DLLs and import libs
+# Has to be a shell function in order to 'eat' the argument
+# that is supplied when $file_magic_command is called.
+func_win32_libid ()
+{
+ win32_libid_type="unknown"
+ win32_fileres=`file -L $1 2>/dev/null`
+ case $win32_fileres in
+ *ar\ archive\ import\ library*) # definitely import
+ win32_libid_type="x86 archive import"
+ ;;
+ *ar\ archive*) # could be an import, or static
+ if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | \
+ $EGREP -e 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then
+ win32_nmres=`eval $NM -f posix -A $1 | \
+ $SED -n -e '1,100{/ I /{s,.*,import,;p;q;};}'`
+ case $win32_nmres in
+ import*) win32_libid_type="x86 archive import";;
+ *) win32_libid_type="x86 archive static";;
+ esac
+ fi
+ ;;
+ *DLL*)
+ win32_libid_type="x86 DLL"
+ ;;
+ *executable*) # but shell scripts are "executable" too...
+ case $win32_fileres in
+ *MS\ Windows\ PE\ Intel*)
+ win32_libid_type="x86 DLL"
+ ;;
+ esac
+ ;;
+ esac
+ $echo $win32_libid_type
+}
+
+
+# func_infer_tag arg
+# Infer tagged configuration to use if any are available and
+# if one wasn't chosen via the "--tag" command line option.
+# Only attempt this if the compiler in the base compile
+# command doesn't match the default compiler.
+# arg is usually of the form 'gcc ...'
+func_infer_tag ()
+{
+ if test -n "$available_tags" && test -z "$tagname"; then
+ CC_quoted=
+ for arg in $CC; do
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ CC_quoted="$CC_quoted $arg"
+ done
+ case $@ in
+ # Blanks in the command may have been stripped by the calling shell,
+ # but not from the CC environment variable when configure was run.
+ " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) ;;
+ # Blanks at the start of $base_compile will cause this to fail
+ # if we don't check for them as well.
+ *)
+ for z in $available_tags; do
+ if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
+ # Evaluate the configuration.
+ eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
+ CC_quoted=
+ for arg in $CC; do
+ # Double-quote args containing other shell metacharacters.
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ CC_quoted="$CC_quoted $arg"
+ done
+ case "$@ " in
+ " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*)
+ # The compiler in the base compile command matches
+ # the one in the tagged configuration.
+ # Assume this is the tagged configuration we want.
+ tagname=$z
+ break
+ ;;
+ esac
+ fi
+ done
+ # If $tagname still isn't set, then no tagged configuration
+ # was found and let the user know that the "--tag" command
+ # line option must be used.
+ if test -z "$tagname"; then
+ $echo "$modename: unable to infer tagged configuration"
+ $echo "$modename: specify a tag with \`--tag'" 1>&2
+ exit $EXIT_FAILURE
+# else
+# $echo "$modename: using $tagname tagged configuration"
+ fi
+ ;;
+ esac
+ fi
+}
+
+
+# func_extract_an_archive dir oldlib
+func_extract_an_archive ()
+{
+ f_ex_an_ar_dir="$1"; shift
+ f_ex_an_ar_oldlib="$1"
+
+ $show "(cd $f_ex_an_ar_dir && $AR x $f_ex_an_ar_oldlib)"
+ $run eval "(cd \$f_ex_an_ar_dir && $AR x \$f_ex_an_ar_oldlib)" || exit $?
+ if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ $echo "$modename: ERROR: object name conflicts: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" 1>&2
+ exit $EXIT_FAILURE
+ fi
+}
+
+# func_extract_archives gentop oldlib ...
+func_extract_archives ()
+{
+ my_gentop="$1"; shift
+ my_oldlibs=${1+"$@"}
+ my_oldobjs=""
+ my_xlib=""
+ my_xabs=""
+ my_xdir=""
+ my_status=""
+
+ $show "${rm}r $my_gentop"
+ $run ${rm}r "$my_gentop"
+ $show "$mkdir $my_gentop"
+ $run $mkdir "$my_gentop"
+ my_status=$?
+ if test "$my_status" -ne 0 && test ! -d "$my_gentop"; then
+ exit $my_status
+ fi
+
+ for my_xlib in $my_oldlibs; do
+ # Extract the objects.
+ case $my_xlib in
+ [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;;
+ *) my_xabs=`pwd`"/$my_xlib" ;;
+ esac
+ my_xlib=`$echo "X$my_xlib" | $Xsed -e 's%^.*/%%'`
+ my_xdir="$my_gentop/$my_xlib"
+
+ $show "${rm}r $my_xdir"
+ $run ${rm}r "$my_xdir"
+ $show "$mkdir $my_xdir"
+ $run $mkdir "$my_xdir"
+ exit_status=$?
+ if test "$exit_status" -ne 0 && test ! -d "$my_xdir"; then
+ exit $exit_status
+ fi
+ case $host in
+ *-darwin*)
+ $show "Extracting $my_xabs"
+ # Do not bother doing anything if just a dry run
+ if test -z "$run"; then
+ darwin_orig_dir=`pwd`
+ cd $my_xdir || exit $?
+ darwin_archive=$my_xabs
+ darwin_curdir=`pwd`
+ darwin_base_archive=`$echo "X$darwin_archive" | $Xsed -e 's%^.*/%%'`
+ darwin_arches=`lipo -info "$darwin_archive" 2>/dev/null | $EGREP Architectures 2>/dev/null`
+ if test -n "$darwin_arches"; then
+ darwin_arches=`echo "$darwin_arches" | $SED -e 's/.*are://'`
+ darwin_arch=
+ $show "$darwin_base_archive has multiple architectures $darwin_arches"
+ for darwin_arch in $darwin_arches ; do
+ mkdir -p "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+ lipo -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}"
+ cd "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+ func_extract_an_archive "`pwd`" "${darwin_base_archive}"
+ cd "$darwin_curdir"
+ $rm "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}"
+ done # $darwin_arches
+ ## Okay now we have a bunch of thin objects, gotta fatten them up :)
+ darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print| xargs basename | sort -u | $NL2SP`
+ darwin_file=
+ darwin_files=
+ for darwin_file in $darwin_filelist; do
+ darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP`
+ lipo -create -output "$darwin_file" $darwin_files
+ done # $darwin_filelist
+ ${rm}r unfat-$$
+ cd "$darwin_orig_dir"
+ else
+ cd "$darwin_orig_dir"
+ func_extract_an_archive "$my_xdir" "$my_xabs"
+ fi # $darwin_arches
+ fi # $run
+ ;;
+ *)
+ func_extract_an_archive "$my_xdir" "$my_xabs"
+ ;;
+ esac
+ my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP`
+ done
+ func_extract_archives_result="$my_oldobjs"
+}
+# End of Shell function definitions
+#####################################
+
+# Darwin sucks
+eval std_shrext=\"$shrext_cmds\"
+
+disable_libs=no
+
+# Parse our command line options once, thoroughly.
+while test "$#" -gt 0
+do
+ arg="$1"
+ shift
+
+ case $arg in
+ -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) optarg= ;;
+ esac
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$prev"; then
+ case $prev in
+ execute_dlfiles)
+ execute_dlfiles="$execute_dlfiles $arg"
+ ;;
+ tag)
+ tagname="$arg"
+ preserve_args="${preserve_args}=$arg"
+
+ # Check whether tagname contains only valid characters
+ case $tagname in
+ *[!-_A-Za-z0-9,/]*)
+ $echo "$progname: invalid tag name: $tagname" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+
+ case $tagname in
+ CC)
+ # Don't test for the "default" C tag, as we know, it's there, but
+ # not specially marked.
+ ;;
+ *)
+ if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "$progpath" > /dev/null; then
+ taglist="$taglist $tagname"
+ # Evaluate the configuration.
+ eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$tagname'$/,/^# ### END LIBTOOL TAG CONFIG: '$tagname'$/p' < $progpath`"
+ else
+ $echo "$progname: ignoring unknown tag $tagname" 1>&2
+ fi
+ ;;
+ esac
+ ;;
+ *)
+ eval "$prev=\$arg"
+ ;;
+ esac
+
+ prev=
+ prevopt=
+ continue
+ fi
+
+ # Have we seen a non-optional argument yet?
+ case $arg in
+ --help)
+ show_help=yes
+ ;;
+
+ --version)
+ $echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP"
+ $echo
+ $echo "Copyright (C) 2005 Free Software Foundation, Inc."
+ $echo "This is free software; see the source for copying conditions. There is NO"
+ $echo "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+ exit $?
+ ;;
+
+ --config)
+ ${SED} -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $progpath
+ # Now print the configurations for the tags.
+ for tagname in $taglist; do
+ ${SED} -n -e "/^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$/,/^# ### END LIBTOOL TAG CONFIG: $tagname$/p" < "$progpath"
+ done
+ exit $?
+ ;;
+
+ --debug)
+ $echo "$progname: enabling shell trace mode"
+ set -x
+ preserve_args="$preserve_args $arg"
+ ;;
+
+ --dry-run | -n)
+ run=:
+ ;;
+
+ --features)
+ $echo "host: $host"
+ if test "$build_libtool_libs" = yes; then
+ $echo "enable shared libraries"
+ else
+ $echo "disable shared libraries"
+ fi
+ if test "$build_old_libs" = yes; then
+ $echo "enable static libraries"
+ else
+ $echo "disable static libraries"
+ fi
+ exit $?
+ ;;
+
+ --finish) mode="finish" ;;
+
+ --mode) prevopt="--mode" prev=mode ;;
+ --mode=*) mode="$optarg" ;;
+
+ --preserve-dup-deps) duplicate_deps="yes" ;;
+
+ --quiet | --silent)
+ show=:
+ preserve_args="$preserve_args $arg"
+ ;;
+
+ --tag)
+ prevopt="--tag"
+ prev=tag
+ preserve_args="$preserve_args --tag"
+ ;;
+ --tag=*)
+ set tag "$optarg" ${1+"$@"}
+ shift
+ prev=tag
+ preserve_args="$preserve_args --tag"
+ ;;
+
+ -dlopen)
+ prevopt="-dlopen"
+ prev=execute_dlfiles
+ ;;
+
+ -*)
+ $echo "$modename: unrecognized option \`$arg'" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+
+ *)
+ nonopt="$arg"
+ break
+ ;;
+ esac
+done
+
+if test -n "$prevopt"; then
+ $echo "$modename: option \`$prevopt' requires an argument" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+fi
+
+case $disable_libs in
+no)
+ ;;
+shared)
+ build_libtool_libs=no
+ build_old_libs=yes
+ ;;
+static)
+ build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
+ ;;
+esac
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end. This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+if test -z "$show_help"; then
+
+ # Infer the operation mode.
+ if test -z "$mode"; then
+ $echo "*** Warning: inferring the mode of operation is deprecated." 1>&2
+ $echo "*** Future versions of Libtool will require --mode=MODE be specified." 1>&2
+ case $nonopt in
+ *cc | cc* | *++ | gcc* | *-gcc* | g++* | xlc*)
+ mode=link
+ for arg
+ do
+ case $arg in
+ -c)
+ mode=compile
+ break
+ ;;
+ esac
+ done
+ ;;
+ *db | *dbx | *strace | *truss)
+ mode=execute
+ ;;
+ *install*|cp|mv)
+ mode=install
+ ;;
+ *rm)
+ mode=uninstall
+ ;;
+ *)
+ # If we have no mode, but dlfiles were specified, then do execute mode.
+ test -n "$execute_dlfiles" && mode=execute
+
+ # Just use the default operation mode.
+ if test -z "$mode"; then
+ if test -n "$nonopt"; then
+ $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2
+ else
+ $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2
+ fi
+ fi
+ ;;
+ esac
+ fi
+
+ # Only execute mode is allowed to have -dlopen flags.
+ if test -n "$execute_dlfiles" && test "$mode" != execute; then
+ $echo "$modename: unrecognized option \`-dlopen'" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Change the help message to a mode-specific one.
+ generic_help="$help"
+ help="Try \`$modename --help --mode=$mode' for more information."
+
+ # These modes are in order of execution frequency so that they run quickly.
+ case $mode in
+ # libtool compile mode
+ compile)
+ modename="$modename: compile"
+ # Get the compilation command and the source file.
+ base_compile=
+ srcfile="$nonopt" # always keep a non-empty value in "srcfile"
+ suppress_opt=yes
+ suppress_output=
+ arg_mode=normal
+ libobj=
+ later=
+
+ for arg
+ do
+ case $arg_mode in
+ arg )
+ # do not "continue". Instead, add this to base_compile
+ lastarg="$arg"
+ arg_mode=normal
+ ;;
+
+ target )
+ libobj="$arg"
+ arg_mode=normal
+ continue
+ ;;
+
+ normal )
+ # Accept any command-line options.
+ case $arg in
+ -o)
+ if test -n "$libobj" ; then
+ $echo "$modename: you cannot specify \`-o' more than once" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ arg_mode=target
+ continue
+ ;;
+
+ -static | -prefer-pic | -prefer-non-pic)
+ later="$later $arg"
+ continue
+ ;;
+
+ -no-suppress)
+ suppress_opt=no
+ continue
+ ;;
+
+ -Xcompiler)
+ arg_mode=arg # the next one goes into the "base_compile" arg list
+ continue # The current "srcfile" will either be retained or
+ ;; # replaced later. I would guess that would be a bug.
+
+ -Wc,*)
+ args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"`
+ lastarg=
+ save_ifs="$IFS"; IFS=','
+ for arg in $args; do
+ IFS="$save_ifs"
+
+ # Double-quote args containing other shell metacharacters.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, so we specify it separately.
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ lastarg="$lastarg $arg"
+ done
+ IFS="$save_ifs"
+ lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"`
+
+ # Add the arguments to base_compile.
+ base_compile="$base_compile $lastarg"
+ continue
+ ;;
+
+ * )
+ # Accept the current argument as the source file.
+ # The previous "srcfile" becomes the current argument.
+ #
+ lastarg="$srcfile"
+ srcfile="$arg"
+ ;;
+ esac # case $arg
+ ;;
+ esac # case $arg_mode
+
+ # Aesthetically quote the previous argument.
+ lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"`
+
+ case $lastarg in
+ # Double-quote args containing other shell metacharacters.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, and some SunOS ksh mistreat backslash-escaping
+ # in scan sets (worked around with variable expansion),
+ # and furthermore cannot handle '|' '&' '(' ')' in scan sets
+ # at all, so we specify them separately.
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ lastarg="\"$lastarg\""
+ ;;
+ esac
+
+ base_compile="$base_compile $lastarg"
+ done # for arg
+
+ case $arg_mode in
+ arg)
+ $echo "$modename: you must specify an argument for -Xcompile"
+ exit $EXIT_FAILURE
+ ;;
+ target)
+ $echo "$modename: you must specify a target with \`-o'" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ *)
+ # Get the name of the library object.
+ [ -z "$libobj" ] && libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'`
+ ;;
+ esac
+
+ # Recognize several different file suffixes.
+ # If the user specifies -o file.o, it is replaced with file.lo
+ xform='[cCFSifmso]'
+ case $libobj in
+ *.ada) xform=ada ;;
+ *.adb) xform=adb ;;
+ *.ads) xform=ads ;;
+ *.asm) xform=asm ;;
+ *.c++) xform=c++ ;;
+ *.cc) xform=cc ;;
+ *.ii) xform=ii ;;
+ *.class) xform=class ;;
+ *.cpp) xform=cpp ;;
+ *.cxx) xform=cxx ;;
+ *.f90) xform=f90 ;;
+ *.for) xform=for ;;
+ *.java) xform=java ;;
+ esac
+
+ libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"`
+
+ case $libobj in
+ *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;;
+ *)
+ $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+
+ func_infer_tag $base_compile
+
+ for arg in $later; do
+ case $arg in
+ -static)
+ build_old_libs=yes
+ continue
+ ;;
+
+ -prefer-pic)
+ pic_mode=yes
+ continue
+ ;;
+
+ -prefer-non-pic)
+ pic_mode=no
+ continue
+ ;;
+ esac
+ done
+
+ qlibobj=`$echo "X$libobj" | $Xsed -e "$sed_quote_subst"`
+ case $qlibobj in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ qlibobj="\"$qlibobj\"" ;;
+ esac
+ test "X$libobj" != "X$qlibobj" \
+ && $echo "X$libobj" | grep '[]~#^*{};<>?"'"'"' &()|`$[]' \
+ && $echo "$modename: libobj name \`$libobj' may not contain shell special characters."
+ objname=`$echo "X$obj" | $Xsed -e 's%^.*/%%'`
+ xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$obj"; then
+ xdir=
+ else
+ xdir=$xdir/
+ fi
+ lobj=${xdir}$objdir/$objname
+
+ if test -z "$base_compile"; then
+ $echo "$modename: you must specify a compilation command" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Delete any leftover library objects.
+ if test "$build_old_libs" = yes; then
+ removelist="$obj $lobj $libobj ${libobj}T"
+ else
+ removelist="$lobj $libobj ${libobj}T"
+ fi
+
+ $run $rm $removelist
+ trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15
+
+ # On Cygwin there's no "real" PIC flag so we must build both object types
+ case $host_os in
+ cygwin* | mingw* | pw32* | os2*)
+ pic_mode=default
+ ;;
+ esac
+ if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then
+ # non-PIC code in shared libraries is not supported
+ pic_mode=default
+ fi
+
+ # Calculate the filename of the output object if compiler does
+ # not support -o with -c
+ if test "$compiler_c_o" = no; then
+ output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext}
+ lockfile="$output_obj.lock"
+ removelist="$removelist $output_obj $lockfile"
+ trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15
+ else
+ output_obj=
+ need_locks=no
+ lockfile=
+ fi
+
+ # Lock this critical section if it is needed
+ # We use this script file to make the link, it avoids creating a new file
+ if test "$need_locks" = yes; then
+ until $run ln "$progpath" "$lockfile" 2>/dev/null; do
+ $show "Waiting for $lockfile to be removed"
+ sleep 2
+ done
+ elif test "$need_locks" = warn; then
+ if test -f "$lockfile"; then
+ $echo "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $run $rm $removelist
+ exit $EXIT_FAILURE
+ fi
+ $echo "$srcfile" > "$lockfile"
+ fi
+
+ if test -n "$fix_srcfile_path"; then
+ eval srcfile=\"$fix_srcfile_path\"
+ fi
+ qsrcfile=`$echo "X$srcfile" | $Xsed -e "$sed_quote_subst"`
+ case $qsrcfile in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ qsrcfile="\"$qsrcfile\"" ;;
+ esac
+
+ $run $rm "$libobj" "${libobj}T"
+
+ # Create a libtool object file (analogous to a ".la" file),
+ # but don't create it if we're doing a dry run.
+ test -z "$run" && cat > ${libobj}T <<EOF
+# $libobj - a libtool object file
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+EOF
+
+ # Only build a PIC object if we are building libtool libraries.
+ if test "$build_libtool_libs" = yes; then
+ # Without this assignment, base_compile gets emptied.
+ fbsd_hideous_sh_bug=$base_compile
+
+ if test "$pic_mode" != no; then
+ command="$base_compile $qsrcfile $pic_flag"
+ else
+ # Don't build PIC code
+ command="$base_compile $qsrcfile"
+ fi
+
+ if test ! -d "${xdir}$objdir"; then
+ $show "$mkdir ${xdir}$objdir"
+ $run $mkdir ${xdir}$objdir
+ exit_status=$?
+ if test "$exit_status" -ne 0 && test ! -d "${xdir}$objdir"; then
+ exit $exit_status
+ fi
+ fi
+
+ if test -z "$output_obj"; then
+ # Place PIC objects in $objdir
+ command="$command -o $lobj"
+ fi
+
+ $run $rm "$lobj" "$output_obj"
+
+ $show "$command"
+ if $run eval "$command"; then :
+ else
+ test -n "$output_obj" && $run $rm $removelist
+ exit $EXIT_FAILURE
+ fi
+
+ if test "$need_locks" = warn &&
+ test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+ $echo "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $run $rm $removelist
+ exit $EXIT_FAILURE
+ fi
+
+ # Just move the object if needed, then go on to compile the next one
+ if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
+ $show "$mv $output_obj $lobj"
+ if $run $mv $output_obj $lobj; then :
+ else
+ error=$?
+ $run $rm $removelist
+ exit $error
+ fi
+ fi
+
+ # Append the name of the PIC object to the libtool object file.
+ test -z "$run" && cat >> ${libobj}T <<EOF
+pic_object='$objdir/$objname'
+
+EOF
+
+ # Allow error messages only from the first compilation.
+ if test "$suppress_opt" = yes; then
+ suppress_output=' >/dev/null 2>&1'
+ fi
+ else
+ # No PIC object so indicate it doesn't exist in the libtool
+ # object file.
+ test -z "$run" && cat >> ${libobj}T <<EOF
+pic_object=none
+
+EOF
+ fi
+
+ # Only build a position-dependent object if we build old libraries.
+ if test "$build_old_libs" = yes; then
+ if test "$pic_mode" != yes; then
+ # Don't build PIC code
+ command="$base_compile $qsrcfile"
+ else
+ command="$base_compile $qsrcfile $pic_flag"
+ fi
+ if test "$compiler_c_o" = yes; then
+ command="$command -o $obj"
+ fi
+
+ # Suppress compiler output if we already did a PIC compilation.
+ command="$command$suppress_output"
+ $run $rm "$obj" "$output_obj"
+ $show "$command"
+ if $run eval "$command"; then :
+ else
+ $run $rm $removelist
+ exit $EXIT_FAILURE
+ fi
+
+ if test "$need_locks" = warn &&
+ test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+ $echo "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $run $rm $removelist
+ exit $EXIT_FAILURE
+ fi
+
+ # Just move the object if needed
+ if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
+ $show "$mv $output_obj $obj"
+ if $run $mv $output_obj $obj; then :
+ else
+ error=$?
+ $run $rm $removelist
+ exit $error
+ fi
+ fi
+
+ # Append the name of the non-PIC object the libtool object file.
+ # Only append if the libtool object file exists.
+ test -z "$run" && cat >> ${libobj}T <<EOF
+# Name of the non-PIC object.
+non_pic_object='$objname'
+
+EOF
+ else
+ # Append the name of the non-PIC object the libtool object file.
+ # Only append if the libtool object file exists.
+ test -z "$run" && cat >> ${libobj}T <<EOF
+# Name of the non-PIC object.
+non_pic_object=none
+
+EOF
+ fi
+
+ $run $mv "${libobj}T" "${libobj}"
+
+ # Unlock the critical section if it was locked
+ if test "$need_locks" != no; then
+ $run $rm "$lockfile"
+ fi
+
+ exit $EXIT_SUCCESS
+ ;;
+
+ # libtool link mode
+ link | relink)
+ modename="$modename: link"
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+ # It is impossible to link a dll without this setting, and
+ # we shouldn't force the makefile maintainer to figure out
+ # which system we are compiling for in order to pass an extra
+ # flag for every libtool invocation.
+ # allow_undefined=no
+
+ # FIXME: Unfortunately, there are problems with the above when trying
+ # to make a dll which has undefined symbols, in which case not
+ # even a static library is built. For now, we need to specify
+ # -no-undefined on the libtool link line when we can be certain
+ # that all symbols are satisfied, otherwise we get a static library.
+ allow_undefined=yes
+ ;;
+ *)
+ allow_undefined=yes
+ ;;
+ esac
+ libtool_args="$nonopt"
+ base_compile="$nonopt $@"
+ compile_command="$nonopt"
+ finalize_command="$nonopt"
+
+ compile_rpath=
+ finalize_rpath=
+ compile_shlibpath=
+ finalize_shlibpath=
+ convenience=
+ old_convenience=
+ deplibs=
+ old_deplibs=
+ compiler_flags=
+ linker_flags=
+ dllsearchpath=
+ lib_search_path=`pwd`
+ inst_prefix_dir=
+
+ avoid_version=no
+ dlfiles=
+ dlprefiles=
+ dlself=no
+ export_dynamic=no
+ export_symbols=
+ export_symbols_regex=
+ generated=
+ libobjs=
+ ltlibs=
+ module=no
+ no_install=no
+ objs=
+ non_pic_objects=
+ notinst_path= # paths that contain not-installed libtool libraries
+ precious_files_regex=
+ prefer_static_libs=no
+ preload=no
+ prev=
+ prevarg=
+ release=
+ rpath=
+ xrpath=
+ perm_rpath=
+ temp_rpath=
+ thread_safe=no
+ vinfo=
+ vinfo_number=no
+
+ func_infer_tag $base_compile
+
+ # We need to know -static, to get the right output filenames.
+ for arg
+ do
+ case $arg in
+ -all-static | -static)
+ if test "X$arg" = "X-all-static"; then
+ if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
+ $echo "$modename: warning: complete static linking is impossible in this configuration" 1>&2
+ fi
+ if test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ prefer_static_libs=yes
+ else
+ if test -z "$pic_flag" && test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ prefer_static_libs=built
+ fi
+ build_libtool_libs=no
+ build_old_libs=yes
+ break
+ ;;
+ esac
+ done
+
+ # See if our shared archives depend on static archives.
+ test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+ # Go through the arguments, transforming them on the way.
+ while test "$#" -gt 0; do
+ arg="$1"
+ shift
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test
+ ;;
+ *) qarg=$arg ;;
+ esac
+ libtool_args="$libtool_args $qarg"
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$prev"; then
+ case $prev in
+ output)
+ compile_command="$compile_command @OUTPUT@"
+ finalize_command="$finalize_command @OUTPUT@"
+ ;;
+ esac
+
+ case $prev in
+ dlfiles|dlprefiles)
+ if test "$preload" = no; then
+ # Add the symbol object into the linking commands.
+ compile_command="$compile_command @SYMFILE@"
+ finalize_command="$finalize_command @SYMFILE@"
+ preload=yes
+ fi
+ case $arg in
+ *.la | *.lo) ;; # We handle these cases below.
+ force)
+ if test "$dlself" = no; then
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ self)
+ if test "$prev" = dlprefiles; then
+ dlself=yes
+ elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
+ dlself=yes
+ else
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ *)
+ if test "$prev" = dlfiles; then
+ dlfiles="$dlfiles $arg"
+ else
+ dlprefiles="$dlprefiles $arg"
+ fi
+ prev=
+ continue
+ ;;
+ esac
+ ;;
+ expsyms)
+ export_symbols="$arg"
+ if test ! -f "$arg"; then
+ $echo "$modename: symbol file \`$arg' does not exist"
+ exit $EXIT_FAILURE
+ fi
+ prev=
+ continue
+ ;;
+ expsyms_regex)
+ export_symbols_regex="$arg"
+ prev=
+ continue
+ ;;
+ inst_prefix)
+ inst_prefix_dir="$arg"
+ prev=
+ continue
+ ;;
+ precious_regex)
+ precious_files_regex="$arg"
+ prev=
+ continue
+ ;;
+ release)
+ release="-$arg"
+ prev=
+ continue
+ ;;
+ objectlist)
+ if test -f "$arg"; then
+ save_arg=$arg
+ moreargs=
+ for fil in `cat $save_arg`
+ do
+# moreargs="$moreargs $fil"
+ arg=$fil
+ # A libtool-controlled object.
+
+ # Check to see that this really is a libtool object.
+ if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ pic_object=
+ non_pic_object=
+
+ # Read the .lo file
+ # If there is no directory component, then add one.
+ case $arg in
+ */* | *\\*) . $arg ;;
+ *) . ./$arg ;;
+ esac
+
+ if test -z "$pic_object" || \
+ test -z "$non_pic_object" ||
+ test "$pic_object" = none && \
+ test "$non_pic_object" = none; then
+ $echo "$modename: cannot find name of object for \`$arg'" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Extract subdirectory from the argument.
+ xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$arg"; then
+ xdir=
+ else
+ xdir="$xdir/"
+ fi
+
+ if test "$pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ pic_object="$xdir$pic_object"
+
+ if test "$prev" = dlfiles; then
+ if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+ dlfiles="$dlfiles $pic_object"
+ prev=
+ continue
+ else
+ # If libtool objects are unsupported, then we need to preload.
+ prev=dlprefiles
+ fi
+ fi
+
+ # CHECK ME: I think I busted this. -Ossama
+ if test "$prev" = dlprefiles; then
+ # Preload the old-style object.
+ dlprefiles="$dlprefiles $pic_object"
+ prev=
+ fi
+
+ # A PIC object.
+ libobjs="$libobjs $pic_object"
+ arg="$pic_object"
+ fi
+
+ # Non-PIC object.
+ if test "$non_pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ non_pic_object="$xdir$non_pic_object"
+
+ # A standard non-PIC object
+ non_pic_objects="$non_pic_objects $non_pic_object"
+ if test -z "$pic_object" || test "$pic_object" = none ; then
+ arg="$non_pic_object"
+ fi
+ else
+ # If the PIC object exists, use it instead.
+ # $xdir was prepended to $pic_object above.
+ non_pic_object="$pic_object"
+ non_pic_objects="$non_pic_objects $non_pic_object"
+ fi
+ else
+ # Only an error if not doing a dry-run.
+ if test -z "$run"; then
+ $echo "$modename: \`$arg' is not a valid libtool object" 1>&2
+ exit $EXIT_FAILURE
+ else
+ # Dry-run case.
+
+ # Extract subdirectory from the argument.
+ xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$arg"; then
+ xdir=
+ else
+ xdir="$xdir/"
+ fi
+
+ pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"`
+ non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"`
+ libobjs="$libobjs $pic_object"
+ non_pic_objects="$non_pic_objects $non_pic_object"
+ fi
+ fi
+ done
+ else
+ $echo "$modename: link input file \`$save_arg' does not exist"
+ exit $EXIT_FAILURE
+ fi
+ arg=$save_arg
+ prev=
+ continue
+ ;;
+ rpath | xrpath)
+ # We need an absolute path.
+ case $arg in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ $echo "$modename: only absolute run-paths are allowed" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+ if test "$prev" = rpath; then
+ case "$rpath " in
+ *" $arg "*) ;;
+ *) rpath="$rpath $arg" ;;
+ esac
+ else
+ case "$xrpath " in
+ *" $arg "*) ;;
+ *) xrpath="$xrpath $arg" ;;
+ esac
+ fi
+ prev=
+ continue
+ ;;
+ xcompiler)
+ compiler_flags="$compiler_flags $qarg"
+ prev=
+ compile_command="$compile_command $qarg"
+ finalize_command="$finalize_command $qarg"
+ continue
+ ;;
+ xlinker)
+ linker_flags="$linker_flags $qarg"
+ compiler_flags="$compiler_flags $wl$qarg"
+ prev=
+ compile_command="$compile_command $wl$qarg"
+ finalize_command="$finalize_command $wl$qarg"
+ continue
+ ;;
+ xcclinker)
+ linker_flags="$linker_flags $qarg"
+ compiler_flags="$compiler_flags $qarg"
+ prev=
+ compile_command="$compile_command $qarg"
+ finalize_command="$finalize_command $qarg"
+ continue
+ ;;
+ shrext)
+ shrext_cmds="$arg"
+ prev=
+ continue
+ ;;
+ darwin_framework|darwin_framework_skip)
+ test "$prev" = "darwin_framework" && compiler_flags="$compiler_flags $arg"
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ prev=
+ continue
+ ;;
+ *)
+ eval "$prev=\"\$arg\""
+ prev=
+ continue
+ ;;
+ esac
+ fi # test -n "$prev"
+
+ prevarg="$arg"
+
+ case $arg in
+ -all-static)
+ if test -n "$link_static_flag"; then
+ compile_command="$compile_command $link_static_flag"
+ finalize_command="$finalize_command $link_static_flag"
+ fi
+ continue
+ ;;
+
+ -allow-undefined)
+ # FIXME: remove this flag sometime in the future.
+ $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2
+ continue
+ ;;
+
+ -avoid-version)
+ avoid_version=yes
+ continue
+ ;;
+
+ -dlopen)
+ prev=dlfiles
+ continue
+ ;;
+
+ -dlpreopen)
+ prev=dlprefiles
+ continue
+ ;;
+
+ -export-dynamic)
+ export_dynamic=yes
+ continue
+ ;;
+
+ -export-symbols | -export-symbols-regex)
+ if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+ $echo "$modename: more than one -exported-symbols argument is not allowed"
+ exit $EXIT_FAILURE
+ fi
+ if test "X$arg" = "X-export-symbols"; then
+ prev=expsyms
+ else
+ prev=expsyms_regex
+ fi
+ continue
+ ;;
+
+ -framework|-arch|-isysroot)
+ case " $CC " in
+ *" ${arg} ${1} "* | *" ${arg} ${1} "*)
+ prev=darwin_framework_skip ;;
+ *) compiler_flags="$compiler_flags $arg"
+ prev=darwin_framework ;;
+ esac
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ continue
+ ;;
+
+ -inst-prefix-dir)
+ prev=inst_prefix
+ continue
+ ;;
+
+ # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
+ # so, if we see these flags be careful not to treat them like -L
+ -L[A-Z][A-Z]*:*)
+ case $with_gcc/$host in
+ no/*-*-irix* | /*-*-irix*)
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ ;;
+ esac
+ continue
+ ;;
+
+ -L*)
+ dir=`$echo "X$arg" | $Xsed -e 's/^-L//'`
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ if test -z "$absdir"; then
+ $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2
+ absdir="$dir"
+ notinst_path="$notinst_path $dir"
+ fi
+ dir="$absdir"
+ ;;
+ esac
+ case "$deplibs " in
+ *" -L$dir "*) ;;
+ *)
+ deplibs="$deplibs -L$dir"
+ lib_search_path="$lib_search_path $dir"
+ ;;
+ esac
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+ testbindir=`$echo "X$dir" | $Xsed -e 's*/lib$*/bin*'`
+ case :$dllsearchpath: in
+ *":$dir:"*) ;;
+ *) dllsearchpath="$dllsearchpath:$dir";;
+ esac
+ case :$dllsearchpath: in
+ *":$testbindir:"*) ;;
+ *) dllsearchpath="$dllsearchpath:$testbindir";;
+ esac
+ ;;
+ esac
+ continue
+ ;;
+
+ -l*)
+ if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos*)
+ # These systems don't actually have a C or math library (as such)
+ continue
+ ;;
+ *-*-os2*)
+ # These systems don't actually have a C library (as such)
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+ # Do not include libc due to us having libc/libc_r.
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # Rhapsody C and math libraries are in the System framework
+ deplibs="$deplibs -framework System"
+ continue
+ ;;
+ *-*-sco3.2v5* | *-*-sco5v6*)
+ # Causes problems with __ctype
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+ # Compiler inserts libc in the correct place for threads to work
+ test "X$arg" = "X-lc" && continue
+ ;;
+ esac
+ elif test "X$arg" = "X-lc_r"; then
+ case $host in
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+ # Do not include libc_r directly, use -pthread flag.
+ continue
+ ;;
+ esac
+ fi
+ deplibs="$deplibs $arg"
+ continue
+ ;;
+
+ # Tru64 UNIX uses -model [arg] to determine the layout of C++
+ # classes, name mangling, and exception handling.
+ -model)
+ compile_command="$compile_command $arg"
+ compiler_flags="$compiler_flags $arg"
+ finalize_command="$finalize_command $arg"
+ prev=xcompiler
+ continue
+ ;;
+
+ -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe)
+ compiler_flags="$compiler_flags $arg"
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ continue
+ ;;
+
+ -module)
+ module=yes
+ continue
+ ;;
+
+ # -64, -mips[0-9] enable 64-bit mode on the SGI compiler
+ # -r[0-9][0-9]* specifies the processor on the SGI compiler
+ # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler
+ # +DA*, +DD* enable 64-bit mode on the HP compiler
+ # -q* pass through compiler args for the IBM compiler
+ # -m* pass through architecture-specific compiler args for GCC
+ # -m*, -t[45]*, -txscale* pass through architecture-specific
+ # compiler args for GCC
+ # -pg pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*|-pg| \
+ -t[45]*|-txscale*|@*)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ compiler_flags="$compiler_flags $arg"
+ continue
+ ;;
+
+ -shrext)
+ prev=shrext
+ continue
+ ;;
+
+ -no-fast-install)
+ fast_install=no
+ continue
+ ;;
+
+ -no-install)
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+ # The PATH hackery in wrapper scripts is required on Windows
+ # in order for the loader to find any dlls it needs.
+ $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2
+ $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2
+ fast_install=no
+ ;;
+ *) no_install=yes ;;
+ esac
+ continue
+ ;;
+
+ -no-undefined)
+ allow_undefined=no
+ continue
+ ;;
+
+ -objectlist)
+ prev=objectlist
+ continue
+ ;;
+
+ -o) prev=output ;;
+
+ -precious-files-regex)
+ prev=precious_regex
+ continue
+ ;;
+
+ -release)
+ prev=release
+ continue
+ ;;
+
+ -rpath)
+ prev=rpath
+ continue
+ ;;
+
+ -R)
+ prev=xrpath
+ continue
+ ;;
+
+ -R*)
+ dir=`$echo "X$arg" | $Xsed -e 's/^-R//'`
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ $echo "$modename: only absolute run-paths are allowed" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+ case "$xrpath " in
+ *" $dir "*) ;;
+ *) xrpath="$xrpath $dir" ;;
+ esac
+ continue
+ ;;
+
+ -static)
+ # The effects of -static are defined in a previous loop.
+ # We used to do the same as -all-static on platforms that
+ # didn't have a PIC flag, but the assumption that the effects
+ # would be equivalent was wrong. It would break on at least
+ # Digital Unix and AIX.
+ continue
+ ;;
+
+ -thread-safe)
+ thread_safe=yes
+ continue
+ ;;
+
+ -version-info)
+ prev=vinfo
+ continue
+ ;;
+ -version-number)
+ prev=vinfo
+ vinfo_number=yes
+ continue
+ ;;
+
+ -Wc,*)
+ args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'`
+ arg=
+ save_ifs="$IFS"; IFS=','
+ for flag in $args; do
+ IFS="$save_ifs"
+ case $flag in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ flag="\"$flag\""
+ ;;
+ esac
+ arg="$arg $wl$flag"
+ compiler_flags="$compiler_flags $flag"
+ done
+ IFS="$save_ifs"
+ arg=`$echo "X$arg" | $Xsed -e "s/^ //"`
+ ;;
+
+ -Wl,*)
+ args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'`
+ arg=
+ save_ifs="$IFS"; IFS=','
+ for flag in $args; do
+ IFS="$save_ifs"
+ case $flag in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ flag="\"$flag\""
+ ;;
+ esac
+ arg="$arg $wl$flag"
+ compiler_flags="$compiler_flags $wl$flag"
+ linker_flags="$linker_flags $flag"
+ done
+ IFS="$save_ifs"
+ arg=`$echo "X$arg" | $Xsed -e "s/^ //"`
+ ;;
+
+ -Xcompiler)
+ prev=xcompiler
+ continue
+ ;;
+
+ -Xlinker)
+ prev=xlinker
+ continue
+ ;;
+
+ -XCClinker)
+ prev=xcclinker
+ continue
+ ;;
+
+ # Some other compiler flag.
+ -* | +*)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ ;;
+
+ *.$objext)
+ # A standard object.
+ objs="$objs $arg"
+ ;;
+
+ *.lo)
+ # A libtool-controlled object.
+
+ # Check to see that this really is a libtool object.
+ if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ pic_object=
+ non_pic_object=
+
+ # Read the .lo file
+ # If there is no directory component, then add one.
+ case $arg in
+ */* | *\\*) . $arg ;;
+ *) . ./$arg ;;
+ esac
+
+ if test -z "$pic_object" || \
+ test -z "$non_pic_object" ||
+ test "$pic_object" = none && \
+ test "$non_pic_object" = none; then
+ $echo "$modename: cannot find name of object for \`$arg'" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Extract subdirectory from the argument.
+ xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$arg"; then
+ xdir=
+ else
+ xdir="$xdir/"
+ fi
+
+ if test "$pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ pic_object="$xdir$pic_object"
+
+ if test "$prev" = dlfiles; then
+ if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+ dlfiles="$dlfiles $pic_object"
+ prev=
+ continue
+ else
+ # If libtool objects are unsupported, then we need to preload.
+ prev=dlprefiles
+ fi
+ fi
+
+ # CHECK ME: I think I busted this. -Ossama
+ if test "$prev" = dlprefiles; then
+ # Preload the old-style object.
+ dlprefiles="$dlprefiles $pic_object"
+ prev=
+ fi
+
+ # A PIC object.
+ libobjs="$libobjs $pic_object"
+ arg="$pic_object"
+ fi
+
+ # Non-PIC object.
+ if test "$non_pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ non_pic_object="$xdir$non_pic_object"
+
+ # A standard non-PIC object
+ non_pic_objects="$non_pic_objects $non_pic_object"
+ if test -z "$pic_object" || test "$pic_object" = none ; then
+ arg="$non_pic_object"
+ fi
+ else
+ # If the PIC object exists, use it instead.
+ # $xdir was prepended to $pic_object above.
+ non_pic_object="$pic_object"
+ non_pic_objects="$non_pic_objects $non_pic_object"
+ fi
+ else
+ # Only an error if not doing a dry-run.
+ if test -z "$run"; then
+ $echo "$modename: \`$arg' is not a valid libtool object" 1>&2
+ exit $EXIT_FAILURE
+ else
+ # Dry-run case.
+
+ # Extract subdirectory from the argument.
+ xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$arg"; then
+ xdir=
+ else
+ xdir="$xdir/"
+ fi
+
+ pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"`
+ non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"`
+ libobjs="$libobjs $pic_object"
+ non_pic_objects="$non_pic_objects $non_pic_object"
+ fi
+ fi
+ ;;
+
+ *.$libext)
+ # An archive.
+ deplibs="$deplibs $arg"
+ old_deplibs="$old_deplibs $arg"
+ continue
+ ;;
+
+ *.la)
+ # A libtool-controlled library.
+
+ if test "$prev" = dlfiles; then
+ # This library was specified with -dlopen.
+ dlfiles="$dlfiles $arg"
+ prev=
+ elif test "$prev" = dlprefiles; then
+ # The library was specified with -dlpreopen.
+ dlprefiles="$dlprefiles $arg"
+ prev=
+ else
+ deplibs="$deplibs $arg"
+ fi
+ continue
+ ;;
+
+ # Some other compiler argument.
+ *)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ ;;
+ esac # arg
+
+ # Now actually substitute the argument into the commands.
+ if test -n "$arg"; then
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ fi
+ done # argument parsing loop
+
+ if test -n "$prev"; then
+ $echo "$modename: the \`$prevarg' option requires an argument" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
+ eval arg=\"$export_dynamic_flag_spec\"
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ fi
+
+ oldlibs=
+ # calculate the name of the file, without its directory
+ outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'`
+ libobjs_save="$libobjs"
+
+ if test -n "$shlibpath_var"; then
+ # get the directories listed in $shlibpath_var
+ eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\`
+ else
+ shlib_search_path=
+ fi
+ eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
+ eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+
+ output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$output_objdir" = "X$output"; then
+ output_objdir="$objdir"
+ else
+ output_objdir="$output_objdir/$objdir"
+ fi
+ # Create the object directory.
+ if test ! -d "$output_objdir"; then
+ $show "$mkdir $output_objdir"
+ $run $mkdir $output_objdir
+ exit_status=$?
+ if test "$exit_status" -ne 0 && test ! -d "$output_objdir"; then
+ exit $exit_status
+ fi
+ fi
+
+ # Determine the type of output
+ case $output in
+ "")
+ $echo "$modename: you must specify an output file" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ *.$libext) linkmode=oldlib ;;
+ *.lo | *.$objext) linkmode=obj ;;
+ *.la) linkmode=lib ;;
+ *) linkmode=prog ;; # Anything else should be a program.
+ esac
+
+ case $host in
+ *cygwin* | *mingw* | *pw32*)
+ # don't eliminate duplications in $postdeps and $predeps
+ duplicate_compiler_generated_deps=yes
+ ;;
+ *)
+ duplicate_compiler_generated_deps=$duplicate_deps
+ ;;
+ esac
+ specialdeplibs=
+
+ libs=
+ # Find all interdependent deplibs by searching for libraries
+ # that are linked more than once (e.g. -la -lb -la)
+ for deplib in $deplibs; do
+ if test "X$duplicate_deps" = "Xyes" ; then
+ case "$libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ libs="$libs $deplib"
+ done
+
+ if test "$linkmode" = lib; then
+ libs="$predeps $libs $compiler_lib_search_path $postdeps"
+
+ # Compute libraries that are listed more than once in $predeps
+ # $postdeps and mark them as special (i.e., whose duplicates are
+ # not to be eliminated).
+ pre_post_deps=
+ if test "X$duplicate_compiler_generated_deps" = "Xyes" ; then
+ for pre_post_dep in $predeps $postdeps; do
+ case "$pre_post_deps " in
+ *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;;
+ esac
+ pre_post_deps="$pre_post_deps $pre_post_dep"
+ done
+ fi
+ pre_post_deps=
+ fi
+
+ deplibs=
+ newdependency_libs=
+ newlib_search_path=
+ need_relink=no # whether we're linking any uninstalled libtool libraries
+ notinst_deplibs= # not-installed libtool libraries
+ case $linkmode in
+ lib)
+ passes="conv link"
+ for file in $dlfiles $dlprefiles; do
+ case $file in
+ *.la) ;;
+ *)
+ $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+ done
+ ;;
+ prog)
+ compile_deplibs=
+ finalize_deplibs=
+ alldeplibs=no
+ newdlfiles=
+ newdlprefiles=
+ passes="conv scan dlopen dlpreopen link"
+ ;;
+ *) passes="conv"
+ ;;
+ esac
+ for pass in $passes; do
+ if test "$linkmode,$pass" = "lib,link" ||
+ test "$linkmode,$pass" = "prog,scan"; then
+ libs="$deplibs"
+ deplibs=
+ fi
+ if test "$linkmode" = prog; then
+ case $pass in
+ dlopen) libs="$dlfiles" ;;
+ dlpreopen) libs="$dlprefiles" ;;
+ link)
+ libs="$deplibs %DEPLIBS%"
+ test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs"
+ ;;
+ esac
+ fi
+ if test "$pass" = dlopen; then
+ # Collect dlpreopened libraries
+ save_deplibs="$deplibs"
+ deplibs=
+ fi
+ for deplib in $libs; do
+ lib=
+ found=no
+ case $deplib in
+ -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe)
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ compiler_flags="$compiler_flags $deplib"
+ fi
+ continue
+ ;;
+ -l*)
+ if test "$linkmode" != lib && test "$linkmode" != prog; then
+ $echo "$modename: warning: \`-l' is ignored for archives/objects" 1>&2
+ continue
+ fi
+ name=`$echo "X$deplib" | $Xsed -e 's/^-l//'`
+ for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ for search_ext in .la $std_shrext .so .a; do
+ # Search the libtool library
+ lib="$searchdir/lib${name}${search_ext}"
+ if test -f "$lib"; then
+ if test "$search_ext" = ".la"; then
+ found=yes
+ else
+ found=no
+ fi
+ break 2
+ fi
+ done
+ done
+ if test "$found" != yes; then
+ # deplib doesn't seem to be a libtool library
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+ fi
+ continue
+ else # deplib is a libtool library
+ # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
+ # We need to do some special things here, and not later.
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $deplib "*)
+ if (${SED} -e '2q' $lib |
+ grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ library_names=
+ old_library=
+ case $lib in
+ */* | *\\*) . $lib ;;
+ *) . ./$lib ;;
+ esac
+ for l in $old_library $library_names; do
+ ll="$l"
+ done
+ if test "X$ll" = "X$old_library" ; then # only static version available
+ found=no
+ ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$ladir" = "X$lib" && ladir="."
+ lib=$ladir/$old_library
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+ fi
+ continue
+ fi
+ fi
+ ;;
+ *) ;;
+ esac
+ fi
+ fi
+ ;; # -l
+ -L*)
+ case $linkmode in
+ lib)
+ deplibs="$deplib $deplibs"
+ test "$pass" = conv && continue
+ newdependency_libs="$deplib $newdependency_libs"
+ newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`
+ ;;
+ prog)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ if test "$pass" = scan; then
+ deplibs="$deplib $deplibs"
+ else
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ fi
+ newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`
+ ;;
+ *)
+ $echo "$modename: warning: \`-L' is ignored for archives/objects" 1>&2
+ ;;
+ esac # linkmode
+ continue
+ ;; # -L
+ -R*)
+ if test "$pass" = link; then
+ dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'`
+ # Make sure the xrpath contains only unique directories.
+ case "$xrpath " in
+ *" $dir "*) ;;
+ *) xrpath="$xrpath $dir" ;;
+ esac
+ fi
+ deplibs="$deplib $deplibs"
+ continue
+ ;;
+ *.la) lib="$deplib" ;;
+ *.$libext)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ case $linkmode in
+ lib)
+ valid_a_lib=no
+ case $deplibs_check_method in
+ match_pattern*)
+ set dummy $deplibs_check_method
+ match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
+ if eval $echo \"$deplib\" 2>/dev/null \
+ | $SED 10q \
+ | $EGREP "$match_pattern_regex" > /dev/null; then
+ valid_a_lib=yes
+ fi
+ ;;
+ pass_all)
+ valid_a_lib=yes
+ ;;
+ esac
+ if test "$valid_a_lib" != yes; then
+ $echo
+ $echo "*** Warning: Trying to link with static lib archive $deplib."
+ $echo "*** I have the capability to make that library automatically link in when"
+ $echo "*** you link to this library. But I can only do this if you have a"
+ $echo "*** shared version of the library, which you do not appear to have"
+ $echo "*** because the file extensions .$libext of this argument makes me believe"
+ $echo "*** that it is just a static archive that I should not used here."
+ else
+ $echo
+ $echo "*** Warning: Linking the shared library $output against the"
+ $echo "*** static library $deplib is not portable!"
+ deplibs="$deplib $deplibs"
+ fi
+ continue
+ ;;
+ prog)
+ if test "$pass" != link; then
+ deplibs="$deplib $deplibs"
+ else
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ fi
+ continue
+ ;;
+ esac # linkmode
+ ;; # *.$libext
+ *.lo | *.$objext)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ elif test "$linkmode" = prog; then
+ if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
+ # If there is no dlopen support or we're linking statically,
+ # we need to preload.
+ newdlprefiles="$newdlprefiles $deplib"
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ newdlfiles="$newdlfiles $deplib"
+ fi
+ fi
+ continue
+ ;;
+ %DEPLIBS%)
+ alldeplibs=yes
+ continue
+ ;;
+ esac # case $deplib
+ if test "$found" = yes || test -f "$lib"; then :
+ else
+ $echo "$modename: cannot find the library \`$lib' or unhandled argument \`$deplib'" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Check to see that this really is a libtool archive.
+ if (${SED} -e '2q' $lib | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+ else
+ $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$ladir" = "X$lib" && ladir="."
+
+ dlname=
+ dlopen=
+ dlpreopen=
+ libdir=
+ library_names=
+ old_library=
+ # If the library was installed with an old release of libtool,
+ # it will not redefine variables installed, or shouldnotlink
+ installed=yes
+ shouldnotlink=no
+ avoidtemprpath=
+
+
+ # Read the .la file
+ case $lib in
+ */* | *\\*) . $lib ;;
+ *) . ./$lib ;;
+ esac
+
+ if test "$linkmode,$pass" = "lib,link" ||
+ test "$linkmode,$pass" = "prog,scan" ||
+ { test "$linkmode" != prog && test "$linkmode" != lib; }; then
+ test -n "$dlopen" && dlfiles="$dlfiles $dlopen"
+ test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen"
+ fi
+
+ if test "$pass" = conv; then
+ # Only check for convenience libraries
+ deplibs="$lib $deplibs"
+ if test -z "$libdir"; then
+ if test -z "$old_library"; then
+ $echo "$modename: cannot find name of link library for \`$lib'" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ # It is a libtool convenience library, so add in its objects.
+ convenience="$convenience $ladir/$objdir/$old_library"
+ old_convenience="$old_convenience $ladir/$objdir/$old_library"
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ deplibs="$deplib $deplibs"
+ if test "X$duplicate_deps" = "Xyes" ; then
+ case "$tmp_libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ tmp_libs="$tmp_libs $deplib"
+ done
+ elif test "$linkmode" != prog && test "$linkmode" != lib; then
+ $echo "$modename: \`$lib' is not a convenience library" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ continue
+ fi # $pass = conv
+
+
+ # Get the name of the library we link against.
+ linklib=
+ for l in $old_library $library_names; do
+ linklib="$l"
+ done
+ if test -z "$linklib"; then
+ $echo "$modename: cannot find name of link library for \`$lib'" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # This library was specified with -dlopen.
+ if test "$pass" = dlopen; then
+ if test -z "$libdir"; then
+ $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ if test -z "$dlname" ||
+ test "$dlopen_support" != yes ||
+ test "$build_libtool_libs" = no; then
+ # If there is no dlname, no dlopen support or we're linking
+ # statically, we need to preload. We also need to preload any
+ # dependent libraries so libltdl's deplib preloader doesn't
+ # bomb out in the load deplibs phase.
+ dlprefiles="$dlprefiles $lib $dependency_libs"
+ else
+ newdlfiles="$newdlfiles $lib"
+ fi
+ continue
+ fi # $pass = dlopen
+
+ # We need an absolute path.
+ case $ladir in
+ [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;;
+ *)
+ abs_ladir=`cd "$ladir" && pwd`
+ if test -z "$abs_ladir"; then
+ $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2
+ $echo "$modename: passing it literally to the linker, although it might fail" 1>&2
+ abs_ladir="$ladir"
+ fi
+ ;;
+ esac
+ laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
+
+ # Find the relevant object directory and library name.
+ if test "X$installed" = Xyes; then
+ if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+ $echo "$modename: warning: library \`$lib' was moved." 1>&2
+ dir="$ladir"
+ absdir="$abs_ladir"
+ libdir="$abs_ladir"
+ else
+ dir="$libdir"
+ absdir="$libdir"
+ fi
+ test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes
+ else
+ if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+ dir="$ladir"
+ absdir="$abs_ladir"
+ # Remove this search path later
+ notinst_path="$notinst_path $abs_ladir"
+ else
+ dir="$ladir/$objdir"
+ absdir="$abs_ladir/$objdir"
+ # Remove this search path later
+ notinst_path="$notinst_path $abs_ladir"
+ fi
+ fi # $installed = yes
+ name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
+
+ # This library was specified with -dlpreopen.
+ if test "$pass" = dlpreopen; then
+ if test -z "$libdir"; then
+ $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ # Prefer using a static library (so that no silly _DYNAMIC symbols
+ # are required to link).
+ if test -n "$old_library"; then
+ newdlprefiles="$newdlprefiles $dir/$old_library"
+ # Otherwise, use the dlname, so that lt_dlopen finds it.
+ elif test -n "$dlname"; then
+ newdlprefiles="$newdlprefiles $dir/$dlname"
+ else
+ newdlprefiles="$newdlprefiles $dir/$linklib"
+ fi
+ fi # $pass = dlpreopen
+
+ if test -z "$libdir"; then
+ # Link the convenience library
+ if test "$linkmode" = lib; then
+ deplibs="$dir/$old_library $deplibs"
+ elif test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$dir/$old_library $compile_deplibs"
+ finalize_deplibs="$dir/$old_library $finalize_deplibs"
+ else
+ deplibs="$lib $deplibs" # used for prog,scan pass
+ fi
+ continue
+ fi
+
+
+ if test "$linkmode" = prog && test "$pass" != link; then
+ newlib_search_path="$newlib_search_path $ladir"
+ deplibs="$lib $deplibs"
+
+ linkalldeplibs=no
+ if test "$link_all_deplibs" != no || test -z "$library_names" ||
+ test "$build_libtool_libs" = no; then
+ linkalldeplibs=yes
+ fi
+
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ case $deplib in
+ -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test
+ esac
+ # Need to link against all dependency_libs?
+ if test "$linkalldeplibs" = yes; then
+ deplibs="$deplib $deplibs"
+ else
+ # Need to hardcode shared library paths
+ # or/and link against static libraries
+ newdependency_libs="$deplib $newdependency_libs"
+ fi
+ if test "X$duplicate_deps" = "Xyes" ; then
+ case "$tmp_libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ tmp_libs="$tmp_libs $deplib"
+ done # for deplib
+ continue
+ fi # $linkmode = prog...
+
+ if test "$linkmode,$pass" = "prog,link"; then
+ if test -n "$library_names" &&
+ { test "$prefer_static_libs" = no || test -z "$old_library"; }; then
+ # We need to hardcode the library path
+ if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then
+ # Make sure the rpath contains only unique directories.
+ case "$temp_rpath " in
+ *" $dir "*) ;;
+ *" $absdir "*) ;;
+ *) temp_rpath="$temp_rpath $absdir" ;;
+ esac
+ fi
+
+ # Hardcode the library path.
+ # Skip directories that are in the system default run-time
+ # search path.
+ case " $sys_lib_dlsearch_path " in
+ *" $absdir "*) ;;
+ *)
+ case "$compile_rpath " in
+ *" $absdir "*) ;;
+ *) compile_rpath="$compile_rpath $absdir"
+ esac
+ ;;
+ esac
+ case " $sys_lib_dlsearch_path " in
+ *" $libdir "*) ;;
+ *)
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir"
+ esac
+ ;;
+ esac
+ fi # $linkmode,$pass = prog,link...
+
+ if test "$alldeplibs" = yes &&
+ { test "$deplibs_check_method" = pass_all ||
+ { test "$build_libtool_libs" = yes &&
+ test -n "$library_names"; }; }; then
+ # We only need to search for static libraries
+ continue
+ fi
+ fi
+
+ link_static=no # Whether the deplib will be linked statically
+ use_static_libs=$prefer_static_libs
+ if test "$use_static_libs" = built && test "$installed" = yes ; then
+ use_static_libs=no
+ fi
+ if test -n "$library_names" &&
+ { test "$use_static_libs" = no || test -z "$old_library"; }; then
+ if test "$installed" = no; then
+ notinst_deplibs="$notinst_deplibs $lib"
+ need_relink=yes
+ fi
+ # This is a shared library
+
+ # Warn about portability, can't link against -module's on
+ # some systems (darwin)
+ if test "$shouldnotlink" = yes && test "$pass" = link ; then
+ $echo
+ if test "$linkmode" = prog; then
+ $echo "*** Warning: Linking the executable $output against the loadable module"
+ else
+ $echo "*** Warning: Linking the shared library $output against the loadable module"
+ fi
+ $echo "*** $linklib is not portable!"
+ fi
+ if test "$linkmode" = lib &&
+ test "$hardcode_into_libs" = yes; then
+ # Hardcode the library path.
+ # Skip directories that are in the system default run-time
+ # search path.
+ case " $sys_lib_dlsearch_path " in
+ *" $absdir "*) ;;
+ *)
+ case "$compile_rpath " in
+ *" $absdir "*) ;;
+ *) compile_rpath="$compile_rpath $absdir"
+ esac
+ ;;
+ esac
+ case " $sys_lib_dlsearch_path " in
+ *" $libdir "*) ;;
+ *)
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir"
+ esac
+ ;;
+ esac
+ fi
+
+ if test -n "$old_archive_from_expsyms_cmds"; then
+ # figure out the soname
+ set dummy $library_names
+ realname="$2"
+ shift; shift
+ libname=`eval \\$echo \"$libname_spec\"`
+ # use dlname if we got it. it's perfectly good, no?
+ if test -n "$dlname"; then
+ soname="$dlname"
+ elif test -n "$soname_spec"; then
+ # bleh windows
+ case $host in
+ *cygwin* | mingw*)
+ major=`expr $current - $age`
+ versuffix="-$major"
+ ;;
+ esac
+ eval soname=\"$soname_spec\"
+ else
+ soname="$realname"
+ fi
+
+ # Make a new name for the extract_expsyms_cmds to use
+ soroot="$soname"
+ soname=`$echo $soroot | ${SED} -e 's/^.*\///'`
+ newlib="libimp-`$echo $soname | ${SED} 's/^lib//;s/\.dll$//'`.a"
+
+ # If the library has no export list, then create one now
+ if test -f "$output_objdir/$soname-def"; then :
+ else
+ $show "extracting exported symbol list from \`$soname'"
+ save_ifs="$IFS"; IFS='~'
+ cmds=$extract_expsyms_cmds
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ fi
+
+ # Create $newlib
+ if test -f "$output_objdir/$newlib"; then :; else
+ $show "generating import library for \`$soname'"
+ save_ifs="$IFS"; IFS='~'
+ cmds=$old_archive_from_expsyms_cmds
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ fi
+ # make sure the library variables are pointing to the new library
+ dir=$output_objdir
+ linklib=$newlib
+ fi # test -n "$old_archive_from_expsyms_cmds"
+
+ if test "$linkmode" = prog || test "$mode" != relink; then
+ add_shlibpath=
+ add_dir=
+ add=
+ lib_linked=yes
+ case $hardcode_action in
+ immediate | unsupported)
+ if test "$hardcode_direct" = no; then
+ add="$dir/$linklib"
+ case $host in
+ *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;;
+ *-*-sysv4*uw2*) add_dir="-L$dir" ;;
+ *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \
+ *-*-unixware7*) add_dir="-L$dir" ;;
+ *-*-darwin* )
+ # if the lib is a module then we can not link against
+ # it, someone is ignoring the new warnings I added
+ if /usr/bin/file -L $add 2> /dev/null |
+ $EGREP ": [^:]* bundle" >/dev/null ; then
+ $echo "** Warning, lib $linklib is a module, not a shared library"
+ if test -z "$old_library" ; then
+ $echo
+ $echo "** And there doesn't seem to be a static archive available"
+ $echo "** The link will probably fail, sorry"
+ else
+ add="$dir/$old_library"
+ fi
+ fi
+ esac
+ elif test "$hardcode_minus_L" = no; then
+ case $host in
+ *-*-sunos*) add_shlibpath="$dir" ;;
+ esac
+ add_dir="-L$dir"
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = no; then
+ add_shlibpath="$dir"
+ add="-l$name"
+ else
+ lib_linked=no
+ fi
+ ;;
+ relink)
+ if test "$hardcode_direct" = yes; then
+ add="$dir/$linklib"
+ elif test "$hardcode_minus_L" = yes; then
+ add_dir="-L$dir"
+ # Try looking first in the location we're being installed to.
+ if test -n "$inst_prefix_dir"; then
+ case $libdir in
+ [\\/]*)
+ add_dir="$add_dir -L$inst_prefix_dir$libdir"
+ ;;
+ esac
+ fi
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = yes; then
+ add_shlibpath="$dir"
+ add="-l$name"
+ else
+ lib_linked=no
+ fi
+ ;;
+ *) lib_linked=no ;;
+ esac
+
+ if test "$lib_linked" != yes; then
+ $echo "$modename: configuration error: unsupported hardcode properties"
+ exit $EXIT_FAILURE
+ fi
+
+ if test -n "$add_shlibpath"; then
+ case :$compile_shlibpath: in
+ *":$add_shlibpath:"*) ;;
+ *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;;
+ esac
+ fi
+ if test "$linkmode" = prog; then
+ test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
+ test -n "$add" && compile_deplibs="$add $compile_deplibs"
+ else
+ test -n "$add_dir" && deplibs="$add_dir $deplibs"
+ test -n "$add" && deplibs="$add $deplibs"
+ if test "$hardcode_direct" != yes && \
+ test "$hardcode_minus_L" != yes && \
+ test "$hardcode_shlibpath_var" = yes; then
+ case :$finalize_shlibpath: in
+ *":$libdir:"*) ;;
+ *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
+ esac
+ fi
+ fi
+ fi
+
+ if test "$linkmode" = prog || test "$mode" = relink; then
+ add_shlibpath=
+ add_dir=
+ add=
+ # Finalize command for both is simple: just hardcode it.
+ if test "$hardcode_direct" = yes; then
+ add="$libdir/$linklib"
+ elif test "$hardcode_minus_L" = yes; then
+ add_dir="-L$libdir"
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = yes; then
+ case :$finalize_shlibpath: in
+ *":$libdir:"*) ;;
+ *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
+ esac
+ add="-l$name"
+ elif test "$hardcode_automatic" = yes; then
+ if test -n "$inst_prefix_dir" &&
+ test -f "$inst_prefix_dir$libdir/$linklib" ; then
+ add="$inst_prefix_dir$libdir/$linklib"
+ else
+ add="$libdir/$linklib"
+ fi
+ else
+ # We cannot seem to hardcode it, guess we'll fake it.
+ add_dir="-L$libdir"
+ # Try looking first in the location we're being installed to.
+ if test -n "$inst_prefix_dir"; then
+ case $libdir in
+ [\\/]*)
+ add_dir="$add_dir -L$inst_prefix_dir$libdir"
+ ;;
+ esac
+ fi
+ add="-l$name"
+ fi
+
+ if test "$linkmode" = prog; then
+ test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
+ test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
+ else
+ test -n "$add_dir" && deplibs="$add_dir $deplibs"
+ test -n "$add" && deplibs="$add $deplibs"
+ fi
+ fi
+ elif test "$linkmode" = prog; then
+ # Here we assume that one of hardcode_direct or hardcode_minus_L
+ # is not unsupported. This is valid on all known static and
+ # shared platforms.
+ if test "$hardcode_direct" != unsupported; then
+ test -n "$old_library" && linklib="$old_library"
+ compile_deplibs="$dir/$linklib $compile_deplibs"
+ finalize_deplibs="$dir/$linklib $finalize_deplibs"
+ else
+ compile_deplibs="-l$name -L$dir $compile_deplibs"
+ finalize_deplibs="-l$name -L$dir $finalize_deplibs"
+ fi
+ elif test "$build_libtool_libs" = yes; then
+ # Not a shared library
+ if test "$deplibs_check_method" != pass_all; then
+ # We're trying link a shared library against a static one
+ # but the system doesn't support it.
+
+ # Just print a warning and add the library to dependency_libs so
+ # that the program can be linked against the static library.
+ $echo
+ $echo "*** Warning: This system can not link to static lib archive $lib."
+ $echo "*** I have the capability to make that library automatically link in when"
+ $echo "*** you link to this library. But I can only do this if you have a"
+ $echo "*** shared version of the library, which you do not appear to have."
+ if test "$module" = yes; then
+ $echo "*** But as you try to build a module library, libtool will still create "
+ $echo "*** a static module, that should work as long as the dlopening application"
+ $echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
+ if test -z "$global_symbol_pipe"; then
+ $echo
+ $echo "*** However, this would only work if libtool was able to extract symbol"
+ $echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+ $echo "*** not find such a program. So, this module is probably useless."
+ $echo "*** \`nm' from GNU binutils and a full rebuild may help."
+ fi
+ if test "$build_old_libs" = no; then
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ fi
+ else
+ deplibs="$dir/$old_library $deplibs"
+ link_static=yes
+ fi
+ fi # link shared/static library?
+
+ if test "$linkmode" = lib; then
+ if test -n "$dependency_libs" &&
+ { test "$hardcode_into_libs" != yes ||
+ test "$build_old_libs" = yes ||
+ test "$link_static" = yes; }; then
+ # Extract -R from dependency_libs
+ temp_deplibs=
+ for libdir in $dependency_libs; do
+ case $libdir in
+ -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'`
+ case " $xrpath " in
+ *" $temp_xrpath "*) ;;
+ *) xrpath="$xrpath $temp_xrpath";;
+ esac;;
+ *) temp_deplibs="$temp_deplibs $libdir";;
+ esac
+ done
+ dependency_libs="$temp_deplibs"
+ fi
+
+ newlib_search_path="$newlib_search_path $absdir"
+ # Link against this library
+ test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+ # ... and its dependency_libs
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ newdependency_libs="$deplib $newdependency_libs"
+ if test "X$duplicate_deps" = "Xyes" ; then
+ case "$tmp_libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ tmp_libs="$tmp_libs $deplib"
+ done
+
+ if test "$link_all_deplibs" != no; then
+ # Add the search paths of all dependency libraries
+ for deplib in $dependency_libs; do
+ case $deplib in
+ -L*) path="$deplib" ;;
+ *.la)
+ dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$dir" = "X$deplib" && dir="."
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ if test -z "$absdir"; then
+ $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2
+ absdir="$dir"
+ fi
+ ;;
+ esac
+ if grep "^installed=no" $deplib > /dev/null; then
+ path="$absdir/$objdir"
+ else
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+ if test -z "$libdir"; then
+ $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ if test "$absdir" != "$libdir"; then
+ $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2
+ fi
+ path="$absdir"
+ fi
+ depdepl=
+ case $host in
+ *-*-darwin*)
+ # we do not want to link against static libs,
+ # but need to link against shared
+ eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
+ if test -n "$deplibrary_names" ; then
+ for tmp in $deplibrary_names ; do
+ depdepl=$tmp
+ done
+ if test -f "$path/$depdepl" ; then
+ depdepl="$path/$depdepl"
+ fi
+ # do not add paths which are already there
+ case " $newlib_search_path " in
+ *" $path "*) ;;
+ *) newlib_search_path="$newlib_search_path $path";;
+ esac
+ fi
+ path=""
+ ;;
+ *)
+ path="-L$path"
+ ;;
+ esac
+ ;;
+ -l*)
+ case $host in
+ *-*-darwin*)
+ # Again, we only want to link against shared libraries
+ eval tmp_libs=`$echo "X$deplib" | $Xsed -e "s,^\-l,,"`
+ for tmp in $newlib_search_path ; do
+ if test -f "$tmp/lib$tmp_libs.dylib" ; then
+ eval depdepl="$tmp/lib$tmp_libs.dylib"
+ break
+ fi
+ done
+ path=""
+ ;;
+ *) continue ;;
+ esac
+ ;;
+ *) continue ;;
+ esac
+ case " $deplibs " in
+ *" $path "*) ;;
+ *) deplibs="$path $deplibs" ;;
+ esac
+ case " $deplibs " in
+ *" $depdepl "*) ;;
+ *) deplibs="$depdepl $deplibs" ;;
+ esac
+ done
+ fi # link_all_deplibs != no
+ fi # linkmode = lib
+ done # for deplib in $libs
+ dependency_libs="$newdependency_libs"
+ if test "$pass" = dlpreopen; then
+ # Link the dlpreopened libraries before other libraries
+ for deplib in $save_deplibs; do
+ deplibs="$deplib $deplibs"
+ done
+ fi
+ if test "$pass" != dlopen; then
+ if test "$pass" != conv; then
+ # Make sure lib_search_path contains only unique directories.
+ lib_search_path=
+ for dir in $newlib_search_path; do
+ case "$lib_search_path " in
+ *" $dir "*) ;;
+ *) lib_search_path="$lib_search_path $dir" ;;
+ esac
+ done
+ newlib_search_path=
+ fi
+
+ if test "$linkmode,$pass" != "prog,link"; then
+ vars="deplibs"
+ else
+ vars="compile_deplibs finalize_deplibs"
+ fi
+ for var in $vars dependency_libs; do
+ # Add libraries to $var in reverse order
+ eval tmp_libs=\"\$$var\"
+ new_libs=
+ for deplib in $tmp_libs; do
+ # FIXME: Pedantically, this is the right thing to do, so
+ # that some nasty dependency loop isn't accidentally
+ # broken:
+ #new_libs="$deplib $new_libs"
+ # Pragmatically, this seems to cause very few problems in
+ # practice:
+ case $deplib in
+ -L*) new_libs="$deplib $new_libs" ;;
+ -R*) ;;
+ *)
+ # And here is the reason: when a library appears more
+ # than once as an explicit dependence of a library, or
+ # is implicitly linked in more than once by the
+ # compiler, it is considered special, and multiple
+ # occurrences thereof are not removed. Compare this
+ # with having the same library being listed as a
+ # dependency of multiple other libraries: in this case,
+ # we know (pedantically, we assume) the library does not
+ # need to be listed more than once, so we keep only the
+ # last copy. This is not always right, but it is rare
+ # enough that we require users that really mean to play
+ # such unportable linking tricks to link the library
+ # using -Wl,-lname, so that libtool does not consider it
+ # for duplicate removal.
+ case " $specialdeplibs " in
+ *" $deplib "*) new_libs="$deplib $new_libs" ;;
+ *)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) new_libs="$deplib $new_libs" ;;
+ esac
+ ;;
+ esac
+ ;;
+ esac
+ done
+ tmp_libs=
+ for deplib in $new_libs; do
+ case $deplib in
+ -L*)
+ case " $tmp_libs " in
+ *" $deplib "*) ;;
+ *) tmp_libs="$tmp_libs $deplib" ;;
+ esac
+ ;;
+ *) tmp_libs="$tmp_libs $deplib" ;;
+ esac
+ done
+ eval $var=\"$tmp_libs\"
+ done # for var
+ fi
+ # Last step: remove runtime libs from dependency_libs
+ # (they stay in deplibs)
+ tmp_libs=
+ for i in $dependency_libs ; do
+ case " $predeps $postdeps $compiler_lib_search_path " in
+ *" $i "*)
+ i=""
+ ;;
+ esac
+ if test -n "$i" ; then
+ tmp_libs="$tmp_libs $i"
+ fi
+ done
+ dependency_libs=$tmp_libs
+ done # for pass
+ if test "$linkmode" = prog; then
+ dlfiles="$newdlfiles"
+ dlprefiles="$newdlprefiles"
+ fi
+
+ case $linkmode in
+ oldlib)
+ if test -n "$deplibs"; then
+ $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2
+ fi
+
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$rpath"; then
+ $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$xrpath"; then
+ $echo "$modename: warning: \`-R' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$vinfo"; then
+ $echo "$modename: warning: \`-version-info/-version-number' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$release"; then
+ $echo "$modename: warning: \`-release' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+ $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2
+ fi
+
+ # Now set the variables for building old libraries.
+ build_libtool_libs=no
+ oldlibs="$output"
+ objs="$objs$old_deplibs"
+ ;;
+
+ lib)
+ # Make sure we only generate libraries of the form `libNAME.la'.
+ case $outputname in
+ lib*)
+ name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
+ eval shared_ext=\"$shrext_cmds\"
+ eval libname=\"$libname_spec\"
+ ;;
+ *)
+ if test "$module" = no; then
+ $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ if test "$need_lib_prefix" != no; then
+ # Add the "lib" prefix for modules if required
+ name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
+ eval shared_ext=\"$shrext_cmds\"
+ eval libname=\"$libname_spec\"
+ else
+ libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
+ fi
+ ;;
+ esac
+
+ if test -n "$objs"; then
+ if test "$deplibs_check_method" != pass_all; then
+ $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1
+ exit $EXIT_FAILURE
+ else
+ $echo
+ $echo "*** Warning: Linking the shared library $output against the non-libtool"
+ $echo "*** objects $objs is not portable!"
+ libobjs="$libobjs $objs"
+ fi
+ fi
+
+ if test "$dlself" != no; then
+ $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2
+ fi
+
+ set dummy $rpath
+ if test "$#" -gt 2; then
+ $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2
+ fi
+ install_libdir="$2"
+
+ oldlibs=
+ if test -z "$rpath"; then
+ if test "$build_libtool_libs" = yes; then
+ # Building a libtool convenience library.
+ # Some compilers have problems with a `.al' extension so
+ # convenience libraries should have the same extension an
+ # archive normally would.
+ oldlibs="$output_objdir/$libname.$libext $oldlibs"
+ build_libtool_libs=convenience
+ build_old_libs=yes
+ fi
+
+ if test -n "$vinfo"; then
+ $echo "$modename: warning: \`-version-info/-version-number' is ignored for convenience libraries" 1>&2
+ fi
+
+ if test -n "$release"; then
+ $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2
+ fi
+ else
+
+ # Parse the version information argument.
+ save_ifs="$IFS"; IFS=':'
+ set dummy $vinfo 0 0 0
+ IFS="$save_ifs"
+
+ if test -n "$8"; then
+ $echo "$modename: too many parameters to \`-version-info'" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # convert absolute version numbers to libtool ages
+ # this retains compatibility with .la files and attempts
+ # to make the code below a bit more comprehensible
+
+ case $vinfo_number in
+ yes)
+ number_major="$2"
+ number_minor="$3"
+ number_revision="$4"
+ #
+ # There are really only two kinds -- those that
+ # use the current revision as the major version
+ # and those that subtract age and use age as
+ # a minor version. But, then there is irix
+ # which has an extra 1 added just for fun
+ #
+ case $version_type in
+ darwin|linux|osf|windows)
+ current=`expr $number_major + $number_minor`
+ age="$number_minor"
+ revision="$number_revision"
+ ;;
+ freebsd-aout|freebsd-elf|sunos)
+ current="$number_major"
+ revision="$number_minor"
+ age="0"
+ ;;
+ irix|nonstopux)
+ current=`expr $number_major + $number_minor - 1`
+ age="$number_minor"
+ revision="$number_minor"
+ ;;
+ *)
+ $echo "$modename: unknown library version type \`$version_type'" 1>&2
+ $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+ ;;
+ no)
+ current="$2"
+ revision="$3"
+ age="$4"
+ ;;
+ esac
+
+ # Check that each of the things are valid numbers.
+ case $current in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ $echo "$modename: CURRENT \`$current' must be a nonnegative integer" 1>&2
+ $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+
+ case $revision in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ $echo "$modename: REVISION \`$revision' must be a nonnegative integer" 1>&2
+ $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+
+ case $age in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ $echo "$modename: AGE \`$age' must be a nonnegative integer" 1>&2
+ $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+
+ if test "$age" -gt "$current"; then
+ $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2
+ $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Calculate the version variables.
+ major=
+ versuffix=
+ verstring=
+ case $version_type in
+ none) ;;
+
+ darwin)
+ # Like Linux, but with the current version available in
+ # verstring for coding it into the library header
+ major=.`expr $current - $age`
+ versuffix="$major.$age.$revision"
+ # Darwin ld doesn't like 0 for these options...
+ minor_current=`expr $current + 1`
+ verstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision"
+ ;;
+
+ freebsd-aout)
+ major=".$current"
+ versuffix=".$current.$revision";
+ ;;
+
+ freebsd-elf)
+ major=".$current"
+ versuffix=".$current";
+ ;;
+
+ irix | nonstopux)
+ major=`expr $current - $age + 1`
+
+ case $version_type in
+ nonstopux) verstring_prefix=nonstopux ;;
+ *) verstring_prefix=sgi ;;
+ esac
+ verstring="$verstring_prefix$major.$revision"
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$revision
+ while test "$loop" -ne 0; do
+ iface=`expr $revision - $loop`
+ loop=`expr $loop - 1`
+ verstring="$verstring_prefix$major.$iface:$verstring"
+ done
+
+ # Before this point, $major must not contain `.'.
+ major=.$major
+ versuffix="$major.$revision"
+ ;;
+
+ linux)
+ major=.`expr $current - $age`
+ versuffix="$major.$age.$revision"
+ ;;
+
+ osf)
+ major=.`expr $current - $age`
+ versuffix=".$current.$age.$revision"
+ verstring="$current.$age.$revision"
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$age
+ while test "$loop" -ne 0; do
+ iface=`expr $current - $loop`
+ loop=`expr $loop - 1`
+ verstring="$verstring:${iface}.0"
+ done
+
+ # Make executables depend on our current version.
+ verstring="$verstring:${current}.0"
+ ;;
+
+ sunos)
+ major=".$current"
+ versuffix=".$current.$revision"
+ ;;
+
+ windows)
+ # Use '-' rather than '.', since we only want one
+ # extension on DOS 8.3 filesystems.
+ major=`expr $current - $age`
+ versuffix="-$major"
+ ;;
+
+ *)
+ $echo "$modename: unknown library version type \`$version_type'" 1>&2
+ $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+
+ # Clear the version info if we defaulted, and they specified a release.
+ if test -z "$vinfo" && test -n "$release"; then
+ major=
+ case $version_type in
+ darwin)
+ # we can't check for "0.0" in archive_cmds due to quoting
+ # problems, so we reset it completely
+ verstring=
+ ;;
+ *)
+ verstring="0.0"
+ ;;
+ esac
+ if test "$need_version" = no; then
+ versuffix=
+ else
+ versuffix=".0.0"
+ fi
+ fi
+
+ # Remove version info from name if versioning should be avoided
+ if test "$avoid_version" = yes && test "$need_version" = no; then
+ major=
+ versuffix=
+ verstring=""
+ fi
+
+ # Check to see if the archive will have undefined symbols.
+ if test "$allow_undefined" = yes; then
+ if test "$allow_undefined_flag" = unsupported; then
+ $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2
+ build_libtool_libs=no
+ build_old_libs=yes
+ fi
+ else
+ # Don't allow undefined symbols.
+ allow_undefined_flag="$no_undefined_flag"
+ fi
+ fi
+
+ if test "$mode" != relink; then
+ # Remove our outputs, but don't remove object files since they
+ # may have been created when compiling PIC objects.
+ removelist=
+ tempremovelist=`$echo "$output_objdir/*"`
+ for p in $tempremovelist; do
+ case $p in
+ *.$objext)
+ ;;
+ $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*)
+ if test "X$precious_files_regex" != "X"; then
+ if echo $p | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
+ then
+ continue
+ fi
+ fi
+ removelist="$removelist $p"
+ ;;
+ *) ;;
+ esac
+ done
+ if test -n "$removelist"; then
+ $show "${rm}r $removelist"
+ $run ${rm}r $removelist
+ fi
+ fi
+
+ # Now set the variables for building old libraries.
+ if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
+ oldlibs="$oldlibs $output_objdir/$libname.$libext"
+
+ # Transform .lo files to .o files.
+ oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP`
+ fi
+
+ # Eliminate all temporary directories.
+ for path in $notinst_path; do
+ lib_search_path=`$echo "$lib_search_path " | ${SED} -e "s% $path % %g"`
+ deplibs=`$echo "$deplibs " | ${SED} -e "s% -L$path % %g"`
+ dependency_libs=`$echo "$dependency_libs " | ${SED} -e "s% -L$path % %g"`
+ done
+
+ if test -n "$xrpath"; then
+ # If the user specified any rpath flags, then add them.
+ temp_xrpath=
+ for libdir in $xrpath; do
+ temp_xrpath="$temp_xrpath -R$libdir"
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir" ;;
+ esac
+ done
+ if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then
+ dependency_libs="$temp_xrpath $dependency_libs"
+ fi
+ fi
+
+ # Make sure dlfiles contains only unique files that won't be dlpreopened
+ old_dlfiles="$dlfiles"
+ dlfiles=
+ for lib in $old_dlfiles; do
+ case " $dlprefiles $dlfiles " in
+ *" $lib "*) ;;
+ *) dlfiles="$dlfiles $lib" ;;
+ esac
+ done
+
+ # Make sure dlprefiles contains only unique files
+ old_dlprefiles="$dlprefiles"
+ dlprefiles=
+ for lib in $old_dlprefiles; do
+ case "$dlprefiles " in
+ *" $lib "*) ;;
+ *) dlprefiles="$dlprefiles $lib" ;;
+ esac
+ done
+
+ if test "$build_libtool_libs" = yes; then
+ if test -n "$rpath"; then
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*)
+ # these systems don't actually have a c library (as such)!
+ ;;
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # Rhapsody C library is in the System framework
+ deplibs="$deplibs -framework System"
+ ;;
+ *-*-netbsd*)
+ # Don't link with libc until the a.out ld.so is fixed.
+ ;;
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+ # Do not include libc due to us having libc/libc_r.
+ ;;
+ *-*-sco3.2v5* | *-*-sco5v6*)
+ # Causes problems with __ctype
+ ;;
+ *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+ # Compiler inserts libc in the correct place for threads to work
+ ;;
+ *)
+ # Add libc to deplibs on all other systems if necessary.
+ if test "$build_libtool_need_lc" = "yes"; then
+ deplibs="$deplibs -lc"
+ fi
+ ;;
+ esac
+ fi
+
+ # Transform deplibs into only deplibs that can be linked in shared.
+ name_save=$name
+ libname_save=$libname
+ release_save=$release
+ versuffix_save=$versuffix
+ major_save=$major
+ # I'm not sure if I'm treating the release correctly. I think
+ # release should show up in the -l (ie -lgmp5) so we don't want to
+ # add it in twice. Is that correct?
+ release=""
+ versuffix=""
+ major=""
+ newdeplibs=
+ droppeddeps=no
+ case $deplibs_check_method in
+ pass_all)
+ # Don't check for shared/static. Everything works.
+ # This might be a little naive. We might want to check
+ # whether the library exists or not. But this is on
+ # osf3 & osf4 and I'm not really sure... Just
+ # implementing what was already the behavior.
+ newdeplibs=$deplibs
+ ;;
+ test_compile)
+ # This code stresses the "libraries are programs" paradigm to its
+ # limits. Maybe even breaks it. We compile a program, linking it
+ # against the deplibs as a proxy for the library. Then we can check
+ # whether they linked in statically or dynamically with ldd.
+ $rm conftest.c
+ cat > conftest.c <<EOF
+ int main() { return 0; }
+EOF
+ $rm conftest
+ $LTCC $LTCFLAGS -o conftest conftest.c $deplibs
+ if test "$?" -eq 0 ; then
+ ldd_output=`ldd conftest`
+ for i in $deplibs; do
+ name=`expr $i : '-l\(.*\)'`
+ # If $name is empty we are operating on a -L argument.
+ if test "$name" != "" && test "$name" -ne "0"; then
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $i "*)
+ newdeplibs="$newdeplibs $i"
+ i=""
+ ;;
+ esac
+ fi
+ if test -n "$i" ; then
+ libname=`eval \\$echo \"$libname_spec\"`
+ deplib_matches=`eval \\$echo \"$library_names_spec\"`
+ set dummy $deplib_matches
+ deplib_match=$2
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+ newdeplibs="$newdeplibs $i"
+ else
+ droppeddeps=yes
+ $echo
+ $echo "*** Warning: dynamic linker does not accept needed library $i."
+ $echo "*** I have the capability to make that library automatically link in when"
+ $echo "*** you link to this library. But I can only do this if you have a"
+ $echo "*** shared version of the library, which I believe you do not have"
+ $echo "*** because a test_compile did reveal that the linker did not use it for"
+ $echo "*** its dynamic dependency list that programs get resolved with at runtime."
+ fi
+ fi
+ else
+ newdeplibs="$newdeplibs $i"
+ fi
+ done
+ else
+ # Error occurred in the first compile. Let's try to salvage
+ # the situation: Compile a separate program for each library.
+ for i in $deplibs; do
+ name=`expr $i : '-l\(.*\)'`
+ # If $name is empty we are operating on a -L argument.
+ if test "$name" != "" && test "$name" != "0"; then
+ $rm conftest
+ $LTCC $LTCFLAGS -o conftest conftest.c $i
+ # Did it work?
+ if test "$?" -eq 0 ; then
+ ldd_output=`ldd conftest`
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $i "*)
+ newdeplibs="$newdeplibs $i"
+ i=""
+ ;;
+ esac
+ fi
+ if test -n "$i" ; then
+ libname=`eval \\$echo \"$libname_spec\"`
+ deplib_matches=`eval \\$echo \"$library_names_spec\"`
+ set dummy $deplib_matches
+ deplib_match=$2
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+ newdeplibs="$newdeplibs $i"
+ else
+ droppeddeps=yes
+ $echo
+ $echo "*** Warning: dynamic linker does not accept needed library $i."
+ $echo "*** I have the capability to make that library automatically link in when"
+ $echo "*** you link to this library. But I can only do this if you have a"
+ $echo "*** shared version of the library, which you do not appear to have"
+ $echo "*** because a test_compile did reveal that the linker did not use this one"
+ $echo "*** as a dynamic dependency that programs can get resolved with at runtime."
+ fi
+ fi
+ else
+ droppeddeps=yes
+ $echo
+ $echo "*** Warning! Library $i is needed by this library but I was not able to"
+ $echo "*** make it link in! You will probably need to install it or some"
+ $echo "*** library that it depends on before this library will be fully"
+ $echo "*** functional. Installing it before continuing would be even better."
+ fi
+ else
+ newdeplibs="$newdeplibs $i"
+ fi
+ done
+ fi
+ ;;
+ file_magic*)
+ set dummy $deplibs_check_method
+ file_magic_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
+ for a_deplib in $deplibs; do
+ name=`expr $a_deplib : '-l\(.*\)'`
+ # If $name is empty we are operating on a -L argument.
+ if test "$name" != "" && test "$name" != "0"; then
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $a_deplib "*)
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ ;;
+ esac
+ fi
+ if test -n "$a_deplib" ; then
+ libname=`eval \\$echo \"$libname_spec\"`
+ for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+ for potent_lib in $potential_libs; do
+ # Follow soft links.
+ if ls -lLd "$potent_lib" 2>/dev/null \
+ | grep " -> " >/dev/null; then
+ continue
+ fi
+ # The statement above tries to avoid entering an
+ # endless loop below, in case of cyclic links.
+ # We might still enter an endless loop, since a link
+ # loop can be closed while we follow links,
+ # but so what?
+ potlib="$potent_lib"
+ while test -h "$potlib" 2>/dev/null; do
+ potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'`
+ case $potliblink in
+ [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
+ *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";;
+ esac
+ done
+ if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \
+ | ${SED} 10q \
+ | $EGREP "$file_magic_regex" > /dev/null; then
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ break 2
+ fi
+ done
+ done
+ fi
+ if test -n "$a_deplib" ; then
+ droppeddeps=yes
+ $echo
+ $echo "*** Warning: linker path does not have real file for library $a_deplib."
+ $echo "*** I have the capability to make that library automatically link in when"
+ $echo "*** you link to this library. But I can only do this if you have a"
+ $echo "*** shared version of the library, which you do not appear to have"
+ $echo "*** because I did check the linker path looking for a file starting"
+ if test -z "$potlib" ; then
+ $echo "*** with $libname but no candidates were found. (...for file magic test)"
+ else
+ $echo "*** with $libname and none of the candidates passed a file format test"
+ $echo "*** using a file magic. Last file checked: $potlib"
+ fi
+ fi
+ else
+ # Add a -L argument.
+ newdeplibs="$newdeplibs $a_deplib"
+ fi
+ done # Gone through all deplibs.
+ ;;
+ match_pattern*)
+ set dummy $deplibs_check_method
+ match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
+ for a_deplib in $deplibs; do
+ name=`expr $a_deplib : '-l\(.*\)'`
+ # If $name is empty we are operating on a -L argument.
+ if test -n "$name" && test "$name" != "0"; then
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $a_deplib "*)
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ ;;
+ esac
+ fi
+ if test -n "$a_deplib" ; then
+ libname=`eval \\$echo \"$libname_spec\"`
+ for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+ for potent_lib in $potential_libs; do
+ potlib="$potent_lib" # see symlink-check above in file_magic test
+ if eval $echo \"$potent_lib\" 2>/dev/null \
+ | ${SED} 10q \
+ | $EGREP "$match_pattern_regex" > /dev/null; then
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ break 2
+ fi
+ done
+ done
+ fi
+ if test -n "$a_deplib" ; then
+ droppeddeps=yes
+ $echo
+ $echo "*** Warning: linker path does not have real file for library $a_deplib."
+ $echo "*** I have the capability to make that library automatically link in when"
+ $echo "*** you link to this library. But I can only do this if you have a"
+ $echo "*** shared version of the library, which you do not appear to have"
+ $echo "*** because I did check the linker path looking for a file starting"
+ if test -z "$potlib" ; then
+ $echo "*** with $libname but no candidates were found. (...for regex pattern test)"
+ else
+ $echo "*** with $libname and none of the candidates passed a file format test"
+ $echo "*** using a regex pattern. Last file checked: $potlib"
+ fi
+ fi
+ else
+ # Add a -L argument.
+ newdeplibs="$newdeplibs $a_deplib"
+ fi
+ done # Gone through all deplibs.
+ ;;
+ none | unknown | *)
+ newdeplibs=""
+ tmp_deplibs=`$echo "X $deplibs" | $Xsed -e 's/ -lc$//' \
+ -e 's/ -[LR][^ ]*//g'`
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ for i in $predeps $postdeps ; do
+ # can't use Xsed below, because $i might contain '/'
+ tmp_deplibs=`$echo "X $tmp_deplibs" | ${SED} -e "1s,^X,," -e "s,$i,,"`
+ done
+ fi
+ if $echo "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' \
+ | grep . >/dev/null; then
+ $echo
+ if test "X$deplibs_check_method" = "Xnone"; then
+ $echo "*** Warning: inter-library dependencies are not supported in this platform."
+ else
+ $echo "*** Warning: inter-library dependencies are not known to be supported."
+ fi
+ $echo "*** All declared inter-library dependencies are being dropped."
+ droppeddeps=yes
+ fi
+ ;;
+ esac
+ versuffix=$versuffix_save
+ major=$major_save
+ release=$release_save
+ libname=$libname_save
+ name=$name_save
+
+ case $host in
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # On Rhapsody replace the C library is the System framework
+ newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'`
+ ;;
+ esac
+
+ if test "$droppeddeps" = yes; then
+ if test "$module" = yes; then
+ $echo
+ $echo "*** Warning: libtool could not satisfy all declared inter-library"
+ $echo "*** dependencies of module $libname. Therefore, libtool will create"
+ $echo "*** a static module, that should work as long as the dlopening"
+ $echo "*** application is linked with the -dlopen flag."
+ if test -z "$global_symbol_pipe"; then
+ $echo
+ $echo "*** However, this would only work if libtool was able to extract symbol"
+ $echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+ $echo "*** not find such a program. So, this module is probably useless."
+ $echo "*** \`nm' from GNU binutils and a full rebuild may help."
+ fi
+ if test "$build_old_libs" = no; then
+ oldlibs="$output_objdir/$libname.$libext"
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ else
+ $echo "*** The inter-library dependencies that have been dropped here will be"
+ $echo "*** automatically added whenever a program is linked with this library"
+ $echo "*** or is declared to -dlopen it."
+
+ if test "$allow_undefined" = no; then
+ $echo
+ $echo "*** Since this library must not contain undefined symbols,"
+ $echo "*** because either the platform does not support them or"
+ $echo "*** it was explicitly requested with -no-undefined,"
+ $echo "*** libtool will only create a static version of it."
+ if test "$build_old_libs" = no; then
+ oldlibs="$output_objdir/$libname.$libext"
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ fi
+ fi
+ fi
+ # Done checking deplibs!
+ deplibs=$newdeplibs
+ fi
+
+
+ # move library search paths that coincide with paths to not yet
+ # installed libraries to the beginning of the library search list
+ new_libs=
+ for path in $notinst_path; do
+ case " $new_libs " in
+ *" -L$path/$objdir "*) ;;
+ *)
+ case " $deplibs " in
+ *" -L$path/$objdir "*)
+ new_libs="$new_libs -L$path/$objdir" ;;
+ esac
+ ;;
+ esac
+ done
+ for deplib in $deplibs; do
+ case $deplib in
+ -L*)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) new_libs="$new_libs $deplib" ;;
+ esac
+ ;;
+ *) new_libs="$new_libs $deplib" ;;
+ esac
+ done
+ deplibs="$new_libs"
+
+
+ # All the library-specific variables (install_libdir is set above).
+ library_names=
+ old_library=
+ dlname=
+
+ # Test again, we may have decided not to build it any more
+ if test "$build_libtool_libs" = yes; then
+ if test "$hardcode_into_libs" = yes; then
+ # Hardcode the library paths
+ hardcode_libdirs=
+ dep_rpath=
+ rpath="$finalize_rpath"
+ test "$mode" != relink && rpath="$compile_rpath$rpath"
+ for libdir in $rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ dep_rpath="$dep_rpath $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$perm_rpath " in
+ *" $libdir "*) ;;
+ *) perm_rpath="$perm_rpath $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ if test -n "$hardcode_libdir_flag_spec_ld"; then
+ eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\"
+ else
+ eval dep_rpath=\"$hardcode_libdir_flag_spec\"
+ fi
+ fi
+ if test -n "$runpath_var" && test -n "$perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $perm_rpath; do
+ rpath="$rpath$dir:"
+ done
+ eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
+ fi
+ test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
+ fi
+
+ shlibpath="$finalize_shlibpath"
+ test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath"
+ if test -n "$shlibpath"; then
+ eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
+ fi
+
+ # Get the real and link names of the library.
+ eval shared_ext=\"$shrext_cmds\"
+ eval library_names=\"$library_names_spec\"
+ set dummy $library_names
+ realname="$2"
+ shift; shift
+
+ if test -n "$soname_spec"; then
+ eval soname=\"$soname_spec\"
+ else
+ soname="$realname"
+ fi
+ if test -z "$dlname"; then
+ dlname=$soname
+ fi
+
+ lib="$output_objdir/$realname"
+ linknames=
+ for link
+ do
+ linknames="$linknames $link"
+ done
+
+ # Use standard objects if they are pic
+ test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
+ $show "generating symbol list for \`$libname.la'"
+ export_symbols="$output_objdir/$libname.exp"
+ $run $rm $export_symbols
+ cmds=$export_symbols_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ if len=`expr "X$cmd" : ".*"` &&
+ test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ skipped_export=false
+ else
+ # The command line is too long to execute in one step.
+ $show "using reloadable object file for export list..."
+ skipped_export=:
+ # Break out early, otherwise skipped_export may be
+ # set to false by a later but shorter cmd.
+ break
+ fi
+ done
+ IFS="$save_ifs"
+ if test -n "$export_symbols_regex"; then
+ $show "$EGREP -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\""
+ $run eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+ $show "$mv \"${export_symbols}T\" \"$export_symbols\""
+ $run eval '$mv "${export_symbols}T" "$export_symbols"'
+ fi
+ fi
+ fi
+
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"'
+ fi
+
+ tmp_deplibs=
+ for test_deplib in $deplibs; do
+ case " $convenience " in
+ *" $test_deplib "*) ;;
+ *)
+ tmp_deplibs="$tmp_deplibs $test_deplib"
+ ;;
+ esac
+ done
+ deplibs="$tmp_deplibs"
+
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec"; then
+ save_libobjs=$libobjs
+ eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+ else
+ gentop="$output_objdir/${outputname}x"
+ generated="$generated $gentop"
+
+ func_extract_archives $gentop $convenience
+ libobjs="$libobjs $func_extract_archives_result"
+ fi
+ fi
+
+ if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
+ eval flag=\"$thread_safe_flag_spec\"
+ linker_flags="$linker_flags $flag"
+ fi
+
+ # Make a backup of the uninstalled library when relinking
+ if test "$mode" = relink; then
+ $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $?
+ fi
+
+ # Do each of the archive commands.
+ if test "$module" = yes && test -n "$module_cmds" ; then
+ if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+ eval test_cmds=\"$module_expsym_cmds\"
+ cmds=$module_expsym_cmds
+ else
+ eval test_cmds=\"$module_cmds\"
+ cmds=$module_cmds
+ fi
+ else
+ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+ eval test_cmds=\"$archive_expsym_cmds\"
+ cmds=$archive_expsym_cmds
+ else
+ eval test_cmds=\"$archive_cmds\"
+ cmds=$archive_cmds
+ fi
+ fi
+
+ if test "X$skipped_export" != "X:" &&
+ len=`expr "X$test_cmds" : ".*" 2>/dev/null` &&
+ test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ :
+ else
+ # The command line is too long to link in one step, link piecewise.
+ $echo "creating reloadable object files..."
+
+ # Save the value of $output and $libobjs because we want to
+ # use them later. If we have whole_archive_flag_spec, we
+ # want to use save_libobjs as it was before
+ # whole_archive_flag_spec was expanded, because we can't
+ # assume the linker understands whole_archive_flag_spec.
+ # This may have to be revisited, in case too many
+ # convenience libraries get linked in and end up exceeding
+ # the spec.
+ if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
+ save_libobjs=$libobjs
+ fi
+ save_output=$output
+ output_la=`$echo "X$output" | $Xsed -e "$basename"`
+
+ # Clear the reloadable object creation command queue and
+ # initialize k to one.
+ test_cmds=
+ concat_cmds=
+ objlist=
+ delfiles=
+ last_robj=
+ k=1
+ output=$output_objdir/$output_la-${k}.$objext
+ # Loop over the list of objects to be linked.
+ for obj in $save_libobjs
+ do
+ eval test_cmds=\"$reload_cmds $objlist $last_robj\"
+ if test "X$objlist" = X ||
+ { len=`expr "X$test_cmds" : ".*" 2>/dev/null` &&
+ test "$len" -le "$max_cmd_len"; }; then
+ objlist="$objlist $obj"
+ else
+ # The command $test_cmds is almost too long, add a
+ # command to the queue.
+ if test "$k" -eq 1 ; then
+ # The first file doesn't have a previous command to add.
+ eval concat_cmds=\"$reload_cmds $objlist $last_robj\"
+ else
+ # All subsequent reloadable object files will link in
+ # the last one created.
+ eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj\"
+ fi
+ last_robj=$output_objdir/$output_la-${k}.$objext
+ k=`expr $k + 1`
+ output=$output_objdir/$output_la-${k}.$objext
+ objlist=$obj
+ len=1
+ fi
+ done
+ # Handle the remaining objects by creating one last
+ # reloadable object file. All subsequent reloadable object
+ # files will link in the last one created.
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\"
+
+ if ${skipped_export-false}; then
+ $show "generating symbol list for \`$libname.la'"
+ export_symbols="$output_objdir/$libname.exp"
+ $run $rm $export_symbols
+ libobjs=$output
+ # Append the command to create the export file.
+ eval concat_cmds=\"\$concat_cmds~$export_symbols_cmds\"
+ fi
+
+ # Set up a command to remove the reloadable object files
+ # after they are used.
+ i=0
+ while test "$i" -lt "$k"
+ do
+ i=`expr $i + 1`
+ delfiles="$delfiles $output_objdir/$output_la-${i}.$objext"
+ done
+
+ $echo "creating a temporary reloadable object file: $output"
+
+ # Loop through the commands generated above and execute them.
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $concat_cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+
+ libobjs=$output
+ # Restore the value of output.
+ output=$save_output
+
+ if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
+ eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+ fi
+ # Expand the library linking commands again to reset the
+ # value of $libobjs for piecewise linking.
+
+ # Do each of the archive commands.
+ if test "$module" = yes && test -n "$module_cmds" ; then
+ if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+ cmds=$module_expsym_cmds
+ else
+ cmds=$module_cmds
+ fi
+ else
+ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+ cmds=$archive_expsym_cmds
+ else
+ cmds=$archive_cmds
+ fi
+ fi
+
+ # Append the command to remove the reloadable object files
+ # to the just-reset $cmds.
+ eval cmds=\"\$cmds~\$rm $delfiles\"
+ fi
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || {
+ lt_exit=$?
+
+ # Restore the uninstalled library and exit
+ if test "$mode" = relink; then
+ $run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)'
+ fi
+
+ exit $lt_exit
+ }
+ done
+ IFS="$save_ifs"
+
+ # Restore the uninstalled library and exit
+ if test "$mode" = relink; then
+ $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $?
+
+ if test -n "$convenience"; then
+ if test -z "$whole_archive_flag_spec"; then
+ $show "${rm}r $gentop"
+ $run ${rm}r "$gentop"
+ fi
+ fi
+
+ exit $EXIT_SUCCESS
+ fi
+
+ # Create links to the real library.
+ for linkname in $linknames; do
+ if test "$realname" != "$linkname"; then
+ $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)"
+ $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $?
+ fi
+ done
+
+ # If -module or -export-dynamic was specified, set the dlname.
+ if test "$module" = yes || test "$export_dynamic" = yes; then
+ # On all known operating systems, these are identical.
+ dlname="$soname"
+ fi
+ fi
+ ;;
+
+ obj)
+ if test -n "$deplibs"; then
+ $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2
+ fi
+
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2
+ fi
+
+ if test -n "$rpath"; then
+ $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2
+ fi
+
+ if test -n "$xrpath"; then
+ $echo "$modename: warning: \`-R' is ignored for objects" 1>&2
+ fi
+
+ if test -n "$vinfo"; then
+ $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2
+ fi
+
+ if test -n "$release"; then
+ $echo "$modename: warning: \`-release' is ignored for objects" 1>&2
+ fi
+
+ case $output in
+ *.lo)
+ if test -n "$objs$old_deplibs"; then
+ $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ libobj="$output"
+ obj=`$echo "X$output" | $Xsed -e "$lo2o"`
+ ;;
+ *)
+ libobj=
+ obj="$output"
+ ;;
+ esac
+
+ # Delete the old objects.
+ $run $rm $obj $libobj
+
+ # Objects from convenience libraries. This assumes
+ # single-version convenience libraries. Whenever we create
+ # different ones for PIC/non-PIC, this we'll have to duplicate
+ # the extraction.
+ reload_conv_objs=
+ gentop=
+ # reload_cmds runs $LD directly, so let us get rid of
+ # -Wl from whole_archive_flag_spec
+ wl=
+
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec"; then
+ eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\"
+ else
+ gentop="$output_objdir/${obj}x"
+ generated="$generated $gentop"
+
+ func_extract_archives $gentop $convenience
+ reload_conv_objs="$reload_objs $func_extract_archives_result"
+ fi
+ fi
+
+ # Create the old-style object.
+ reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
+
+ output="$obj"
+ cmds=$reload_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+
+ # Exit if we aren't doing a library object file.
+ if test -z "$libobj"; then
+ if test -n "$gentop"; then
+ $show "${rm}r $gentop"
+ $run ${rm}r $gentop
+ fi
+
+ exit $EXIT_SUCCESS
+ fi
+
+ if test "$build_libtool_libs" != yes; then
+ if test -n "$gentop"; then
+ $show "${rm}r $gentop"
+ $run ${rm}r $gentop
+ fi
+
+ # Create an invalid libtool object if no PIC, so that we don't
+ # accidentally link it into a program.
+ # $show "echo timestamp > $libobj"
+ # $run eval "echo timestamp > $libobj" || exit $?
+ exit $EXIT_SUCCESS
+ fi
+
+ if test -n "$pic_flag" || test "$pic_mode" != default; then
+ # Only do commands if we really have different PIC objects.
+ reload_objs="$libobjs $reload_conv_objs"
+ output="$libobj"
+ cmds=$reload_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ fi
+
+ if test -n "$gentop"; then
+ $show "${rm}r $gentop"
+ $run ${rm}r $gentop
+ fi
+
+ exit $EXIT_SUCCESS
+ ;;
+
+ prog)
+ case $host in
+ *cygwin*) output=`$echo $output | ${SED} -e 's,.exe$,,;s,$,.exe,'` ;;
+ esac
+ if test -n "$vinfo"; then
+ $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2
+ fi
+
+ if test -n "$release"; then
+ $echo "$modename: warning: \`-release' is ignored for programs" 1>&2
+ fi
+
+ if test "$preload" = yes; then
+ if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown &&
+ test "$dlopen_self_static" = unknown; then
+ $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support."
+ fi
+ fi
+
+ case $host in
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # On Rhapsody replace the C library is the System framework
+ compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'`
+ finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'`
+ ;;
+ esac
+
+ case $host in
+ *darwin*)
+ # Don't allow lazy linking, it breaks C++ global constructors
+ if test "$tagname" = CXX ; then
+ compile_command="$compile_command ${wl}-bind_at_load"
+ finalize_command="$finalize_command ${wl}-bind_at_load"
+ fi
+ ;;
+ esac
+
+
+ # move library search paths that coincide with paths to not yet
+ # installed libraries to the beginning of the library search list
+ new_libs=
+ for path in $notinst_path; do
+ case " $new_libs " in
+ *" -L$path/$objdir "*) ;;
+ *)
+ case " $compile_deplibs " in
+ *" -L$path/$objdir "*)
+ new_libs="$new_libs -L$path/$objdir" ;;
+ esac
+ ;;
+ esac
+ done
+ for deplib in $compile_deplibs; do
+ case $deplib in
+ -L*)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) new_libs="$new_libs $deplib" ;;
+ esac
+ ;;
+ *) new_libs="$new_libs $deplib" ;;
+ esac
+ done
+ compile_deplibs="$new_libs"
+
+
+ compile_command="$compile_command $compile_deplibs"
+ finalize_command="$finalize_command $finalize_deplibs"
+
+ if test -n "$rpath$xrpath"; then
+ # If the user specified any rpath flags, then add them.
+ for libdir in $rpath $xrpath; do
+ # This is the magic to use -rpath.
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir" ;;
+ esac
+ done
+ fi
+
+ # Now hardcode the library paths
+ rpath=
+ hardcode_libdirs=
+ for libdir in $compile_rpath $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ rpath="$rpath $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$perm_rpath " in
+ *" $libdir "*) ;;
+ *) perm_rpath="$perm_rpath $libdir" ;;
+ esac
+ fi
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+ testbindir=`$echo "X$libdir" | $Xsed -e 's*/lib$*/bin*'`
+ case :$dllsearchpath: in
+ *":$libdir:"*) ;;
+ *) dllsearchpath="$dllsearchpath:$libdir";;
+ esac
+ case :$dllsearchpath: in
+ *":$testbindir:"*) ;;
+ *) dllsearchpath="$dllsearchpath:$testbindir";;
+ esac
+ ;;
+ esac
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ eval rpath=\" $hardcode_libdir_flag_spec\"
+ fi
+ compile_rpath="$rpath"
+
+ rpath=
+ hardcode_libdirs=
+ for libdir in $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ rpath="$rpath $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$finalize_perm_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ eval rpath=\" $hardcode_libdir_flag_spec\"
+ fi
+ finalize_rpath="$rpath"
+
+ if test -n "$libobjs" && test "$build_old_libs" = yes; then
+ # Transform all the library objects into standard objects.
+ compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+ finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+ fi
+
+ dlsyms=
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ if test -n "$NM" && test -n "$global_symbol_pipe"; then
+ dlsyms="${outputname}S.c"
+ else
+ $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2
+ fi
+ fi
+
+ if test -n "$dlsyms"; then
+ case $dlsyms in
+ "") ;;
+ *.c)
+ # Discover the nlist of each of the dlfiles.
+ nlist="$output_objdir/${outputname}.nm"
+
+ $show "$rm $nlist ${nlist}S ${nlist}T"
+ $run $rm "$nlist" "${nlist}S" "${nlist}T"
+
+ # Parse the name list into a source file.
+ $show "creating $output_objdir/$dlsyms"
+
+ test -z "$run" && $echo > "$output_objdir/$dlsyms" "\
+/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */
+/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+/* Prevent the only kind of declaration conflicts we can make. */
+#define lt_preloaded_symbols some_other_symbol
+
+/* External symbol declarations for the compiler. */\
+"
+
+ if test "$dlself" = yes; then
+ $show "generating symbol list for \`$output'"
+
+ test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist"
+
+ # Add our own program objects to the symbol list.
+ progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+ for arg in $progfiles; do
+ $show "extracting global C symbols from \`$arg'"
+ $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
+ done
+
+ if test -n "$exclude_expsyms"; then
+ $run eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
+ $run eval '$mv "$nlist"T "$nlist"'
+ fi
+
+ if test -n "$export_symbols_regex"; then
+ $run eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
+ $run eval '$mv "$nlist"T "$nlist"'
+ fi
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ export_symbols="$output_objdir/$outputname.exp"
+ $run $rm $export_symbols
+ $run eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+ case $host in
+ *cygwin* | *mingw* )
+ $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+ $run eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"'
+ ;;
+ esac
+ else
+ $run eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
+ $run eval 'grep -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
+ $run eval 'mv "$nlist"T "$nlist"'
+ case $host in
+ *cygwin* | *mingw* )
+ $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+ $run eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
+ ;;
+ esac
+ fi
+ fi
+
+ for arg in $dlprefiles; do
+ $show "extracting global C symbols from \`$arg'"
+ name=`$echo "$arg" | ${SED} -e 's%^.*/%%'`
+ $run eval '$echo ": $name " >> "$nlist"'
+ $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
+ done
+
+ if test -z "$run"; then
+ # Make sure we have at least an empty file.
+ test -f "$nlist" || : > "$nlist"
+
+ if test -n "$exclude_expsyms"; then
+ $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+ $mv "$nlist"T "$nlist"
+ fi
+
+ # Try sorting and uniquifying the output.
+ if grep -v "^: " < "$nlist" |
+ if sort -k 3 </dev/null >/dev/null 2>&1; then
+ sort -k 3
+ else
+ sort +2
+ fi |
+ uniq > "$nlist"S; then
+ :
+ else
+ grep -v "^: " < "$nlist" > "$nlist"S
+ fi
+
+ if test -f "$nlist"S; then
+ eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"'
+ else
+ $echo '/* NONE */' >> "$output_objdir/$dlsyms"
+ fi
+
+ $echo >> "$output_objdir/$dlsyms" "\
+
+#undef lt_preloaded_symbols
+
+#if defined (__STDC__) && __STDC__
+# define lt_ptr void *
+#else
+# define lt_ptr char *
+# define const
+#endif
+
+/* The mapping between symbol names and symbols. */
+"
+
+ case $host in
+ *cygwin* | *mingw* )
+ $echo >> "$output_objdir/$dlsyms" "\
+/* DATA imports from DLLs on WIN32 can't be const, because
+ runtime relocations are performed -- see ld's documentation
+ on pseudo-relocs */
+struct {
+"
+ ;;
+ * )
+ $echo >> "$output_objdir/$dlsyms" "\
+const struct {
+"
+ ;;
+ esac
+
+
+ $echo >> "$output_objdir/$dlsyms" "\
+ const char *name;
+ lt_ptr address;
+}
+lt_preloaded_symbols[] =
+{\
+"
+
+ eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms"
+
+ $echo >> "$output_objdir/$dlsyms" "\
+ {0, (lt_ptr) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+ fi
+
+ pic_flag_for_symtable=
+ case $host in
+ # compiling the symbol table file with pic_flag works around
+ # a FreeBSD bug that causes programs to crash when -lm is
+ # linked before any other PIC object. But we must not use
+ # pic_flag when linking with -static. The problem exists in
+ # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+ *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
+ case "$compile_command " in
+ *" -static "*) ;;
+ *) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND";;
+ esac;;
+ *-*-hpux*)
+ case "$compile_command " in
+ *" -static "*) ;;
+ *) pic_flag_for_symtable=" $pic_flag";;
+ esac
+ esac
+
+ # Now compile the dynamic symbol file.
+ $show "(cd $output_objdir && $LTCC $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")"
+ $run eval '(cd $output_objdir && $LTCC $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $?
+
+ # Clean up the generated files.
+ $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T"
+ $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T"
+
+ # Transform the symbol file into the correct name.
+ case $host in
+ *cygwin* | *mingw* )
+ if test -f "$output_objdir/${outputname}.def" ; then
+ compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%"`
+ finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%"`
+ else
+ compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
+ finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
+ fi
+ ;;
+ * )
+ compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
+ finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
+ ;;
+ esac
+ ;;
+ *)
+ $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+ else
+ # We keep going just in case the user didn't refer to
+ # lt_preloaded_symbols. The linker will fail if global_symbol_pipe
+ # really was required.
+
+ # Nullify the symbol file.
+ compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"`
+ finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"`
+ fi
+
+ if test "$need_relink" = no || test "$build_libtool_libs" != yes; then
+ # Replace the output file specification.
+ compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
+ link_command="$compile_command$compile_rpath"
+
+ # We have no uninstalled library dependencies, so finalize right now.
+ $show "$link_command"
+ $run eval "$link_command"
+ exit_status=$?
+
+ # Delete the generated files.
+ if test -n "$dlsyms"; then
+ $show "$rm $output_objdir/${outputname}S.${objext}"
+ $run $rm "$output_objdir/${outputname}S.${objext}"
+ fi
+
+ exit $exit_status
+ fi
+
+ if test -n "$shlibpath_var"; then
+ # We should set the shlibpath_var
+ rpath=
+ for dir in $temp_rpath; do
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*)
+ # Absolute path.
+ rpath="$rpath$dir:"
+ ;;
+ *)
+ # Relative path: add a thisdir entry.
+ rpath="$rpath\$thisdir/$dir:"
+ ;;
+ esac
+ done
+ temp_rpath="$rpath"
+ fi
+
+ if test -n "$compile_shlibpath$finalize_shlibpath"; then
+ compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+ fi
+ if test -n "$finalize_shlibpath"; then
+ finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+ fi
+
+ compile_var=
+ finalize_var=
+ if test -n "$runpath_var"; then
+ if test -n "$perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $perm_rpath; do
+ rpath="$rpath$dir:"
+ done
+ compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ if test -n "$finalize_perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $finalize_perm_rpath; do
+ rpath="$rpath$dir:"
+ done
+ finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ fi
+
+ if test "$no_install" = yes; then
+ # We don't need to create a wrapper script.
+ link_command="$compile_var$compile_command$compile_rpath"
+ # Replace the output file specification.
+ link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
+ # Delete the old output file.
+ $run $rm $output
+ # Link the executable and exit
+ $show "$link_command"
+ $run eval "$link_command" || exit $?
+ exit $EXIT_SUCCESS
+ fi
+
+ if test "$hardcode_action" = relink; then
+ # Fast installation is not supported
+ link_command="$compile_var$compile_command$compile_rpath"
+ relink_command="$finalize_var$finalize_command$finalize_rpath"
+
+ $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2
+ $echo "$modename: \`$output' will be relinked during installation" 1>&2
+ else
+ if test "$fast_install" != no; then
+ link_command="$finalize_var$compile_command$finalize_rpath"
+ if test "$fast_install" = yes; then
+ relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'`
+ else
+ # fast_install is set to needless
+ relink_command=
+ fi
+ else
+ link_command="$compile_var$compile_command$compile_rpath"
+ relink_command="$finalize_var$finalize_command$finalize_rpath"
+ fi
+ fi
+
+ # Replace the output file specification.
+ link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+
+ # Delete the old output files.
+ $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+ $show "$link_command"
+ $run eval "$link_command" || exit $?
+
+ # Now create the wrapper script.
+ $show "creating $output"
+
+ # Quote the relink command for shipping.
+ if test -n "$relink_command"; then
+ # Preserve any variables that may affect compiler behavior
+ for var in $variables_saved_for_relink; do
+ if eval test -z \"\${$var+set}\"; then
+ relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command"
+ elif eval var_value=\$$var; test -z "$var_value"; then
+ relink_command="$var=; export $var; $relink_command"
+ else
+ var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"`
+ relink_command="$var=\"$var_value\"; export $var; $relink_command"
+ fi
+ done
+ relink_command="(cd `pwd`; $relink_command)"
+ relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"`
+ fi
+
+ # Quote $echo for shipping.
+ if test "X$echo" = "X$SHELL $progpath --fallback-echo"; then
+ case $progpath in
+ [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";;
+ *) qecho="$SHELL `pwd`/$progpath --fallback-echo";;
+ esac
+ qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"`
+ else
+ qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"`
+ fi
+
+ # Only actually do things if our run command is non-null.
+ if test -z "$run"; then
+ # win32 will think the script is a binary if it has
+ # a .exe suffix, so we strip it off here.
+ case $output in
+ *.exe) output=`$echo $output|${SED} 's,.exe$,,'` ;;
+ esac
+ # test for cygwin because mv fails w/o .exe extensions
+ case $host in
+ *cygwin*)
+ exeext=.exe
+ outputname=`$echo $outputname|${SED} 's,.exe$,,'` ;;
+ *) exeext= ;;
+ esac
+ case $host in
+ *cygwin* | *mingw* )
+ output_name=`basename $output`
+ output_path=`dirname $output`
+ cwrappersource="$output_path/$objdir/lt-$output_name.c"
+ cwrapper="$output_path/$output_name.exe"
+ $rm $cwrappersource $cwrapper
+ trap "$rm $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
+
+ cat > $cwrappersource <<EOF
+
+/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
+ Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+
+ The $output program cannot be directly executed until all the libtool
+ libraries that it depends on are installed.
+
+ This wrapper executable should never be moved out of the build directory.
+ If it is, it will not operate correctly.
+
+ Currently, it simply execs the wrapper *script* "/bin/sh $output",
+ but could eventually absorb all of the scripts functionality and
+ exec $objdir/$outputname directly.
+*/
+EOF
+ cat >> $cwrappersource<<"EOF"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/stat.h>
+
+#if defined(PATH_MAX)
+# define LT_PATHMAX PATH_MAX
+#elif defined(MAXPATHLEN)
+# define LT_PATHMAX MAXPATHLEN
+#else
+# define LT_PATHMAX 1024
+#endif
+
+#ifndef DIR_SEPARATOR
+# define DIR_SEPARATOR '/'
+# define PATH_SEPARATOR ':'
+#endif
+
+#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \
+ defined (__OS2__)
+# define HAVE_DOS_BASED_FILE_SYSTEM
+# ifndef DIR_SEPARATOR_2
+# define DIR_SEPARATOR_2 '\\'
+# endif
+# ifndef PATH_SEPARATOR_2
+# define PATH_SEPARATOR_2 ';'
+# endif
+#endif
+
+#ifndef DIR_SEPARATOR_2
+# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+#else /* DIR_SEPARATOR_2 */
+# define IS_DIR_SEPARATOR(ch) \
+ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+#endif /* DIR_SEPARATOR_2 */
+
+#ifndef PATH_SEPARATOR_2
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR)
+#else /* PATH_SEPARATOR_2 */
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2)
+#endif /* PATH_SEPARATOR_2 */
+
+#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type)))
+#define XFREE(stale) do { \
+ if (stale) { free ((void *) stale); stale = 0; } \
+} while (0)
+
+/* -DDEBUG is fairly common in CFLAGS. */
+#undef DEBUG
+#if defined DEBUGWRAPPER
+# define DEBUG(format, ...) fprintf(stderr, format, __VA_ARGS__)
+#else
+# define DEBUG(format, ...)
+#endif
+
+const char *program_name = NULL;
+
+void * xmalloc (size_t num);
+char * xstrdup (const char *string);
+const char * base_name (const char *name);
+char * find_executable(const char *wrapper);
+int check_executable(const char *path);
+char * strendzap(char *str, const char *pat);
+void lt_fatal (const char *message, ...);
+
+int
+main (int argc, char *argv[])
+{
+ char **newargz;
+ int i;
+
+ program_name = (char *) xstrdup (base_name (argv[0]));
+ DEBUG("(main) argv[0] : %s\n",argv[0]);
+ DEBUG("(main) program_name : %s\n",program_name);
+ newargz = XMALLOC(char *, argc+2);
+EOF
+
+ cat >> $cwrappersource <<EOF
+ newargz[0] = (char *) xstrdup("$SHELL");
+EOF
+
+ cat >> $cwrappersource <<"EOF"
+ newargz[1] = find_executable(argv[0]);
+ if (newargz[1] == NULL)
+ lt_fatal("Couldn't find %s", argv[0]);
+ DEBUG("(main) found exe at : %s\n",newargz[1]);
+ /* we know the script has the same name, without the .exe */
+ /* so make sure newargz[1] doesn't end in .exe */
+ strendzap(newargz[1],".exe");
+ for (i = 1; i < argc; i++)
+ newargz[i+1] = xstrdup(argv[i]);
+ newargz[argc+1] = NULL;
+
+ for (i=0; i<argc+1; i++)
+ {
+ DEBUG("(main) newargz[%d] : %s\n",i,newargz[i]);
+ ;
+ }
+
+EOF
+
+ case $host_os in
+ mingw*)
+ cat >> $cwrappersource <<EOF
+ execv("$SHELL",(char const **)newargz);
+EOF
+ ;;
+ *)
+ cat >> $cwrappersource <<EOF
+ execv("$SHELL",newargz);
+EOF
+ ;;
+ esac
+
+ cat >> $cwrappersource <<"EOF"
+ return 127;
+}
+
+void *
+xmalloc (size_t num)
+{
+ void * p = (void *) malloc (num);
+ if (!p)
+ lt_fatal ("Memory exhausted");
+
+ return p;
+}
+
+char *
+xstrdup (const char *string)
+{
+ return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL
+;
+}
+
+const char *
+base_name (const char *name)
+{
+ const char *base;
+
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+ /* Skip over the disk name in MSDOS pathnames. */
+ if (isalpha ((unsigned char)name[0]) && name[1] == ':')
+ name += 2;
+#endif
+
+ for (base = name; *name; name++)
+ if (IS_DIR_SEPARATOR (*name))
+ base = name + 1;
+ return base;
+}
+
+int
+check_executable(const char * path)
+{
+ struct stat st;
+
+ DEBUG("(check_executable) : %s\n", path ? (*path ? path : "EMPTY!") : "NULL!");
+ if ((!path) || (!*path))
+ return 0;
+
+ if ((stat (path, &st) >= 0) &&
+ (
+ /* MinGW & native WIN32 do not support S_IXOTH or S_IXGRP */
+#if defined (S_IXOTH)
+ ((st.st_mode & S_IXOTH) == S_IXOTH) ||
+#endif
+#if defined (S_IXGRP)
+ ((st.st_mode & S_IXGRP) == S_IXGRP) ||
+#endif
+ ((st.st_mode & S_IXUSR) == S_IXUSR))
+ )
+ return 1;
+ else
+ return 0;
+}
+
+/* Searches for the full path of the wrapper. Returns
+ newly allocated full path name if found, NULL otherwise */
+char *
+find_executable (const char* wrapper)
+{
+ int has_slash = 0;
+ const char* p;
+ const char* p_next;
+ /* static buffer for getcwd */
+ char tmp[LT_PATHMAX + 1];
+ int tmp_len;
+ char* concat_name;
+
+ DEBUG("(find_executable) : %s\n", wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!");
+
+ if ((wrapper == NULL) || (*wrapper == '\0'))
+ return NULL;
+
+ /* Absolute path? */
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+ if (isalpha ((unsigned char)wrapper[0]) && wrapper[1] == ':')
+ {
+ concat_name = xstrdup (wrapper);
+ if (check_executable(concat_name))
+ return concat_name;
+ XFREE(concat_name);
+ }
+ else
+ {
+#endif
+ if (IS_DIR_SEPARATOR (wrapper[0]))
+ {
+ concat_name = xstrdup (wrapper);
+ if (check_executable(concat_name))
+ return concat_name;
+ XFREE(concat_name);
+ }
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+ }
+#endif
+
+ for (p = wrapper; *p; p++)
+ if (*p == '/')
+ {
+ has_slash = 1;
+ break;
+ }
+ if (!has_slash)
+ {
+ /* no slashes; search PATH */
+ const char* path = getenv ("PATH");
+ if (path != NULL)
+ {
+ for (p = path; *p; p = p_next)
+ {
+ const char* q;
+ size_t p_len;
+ for (q = p; *q; q++)
+ if (IS_PATH_SEPARATOR(*q))
+ break;
+ p_len = q - p;
+ p_next = (*q == '\0' ? q : q + 1);
+ if (p_len == 0)
+ {
+ /* empty path: current directory */
+ if (getcwd (tmp, LT_PATHMAX) == NULL)
+ lt_fatal ("getcwd failed");
+ tmp_len = strlen(tmp);
+ concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1);
+ memcpy (concat_name, tmp, tmp_len);
+ concat_name[tmp_len] = '/';
+ strcpy (concat_name + tmp_len + 1, wrapper);
+ }
+ else
+ {
+ concat_name = XMALLOC(char, p_len + 1 + strlen(wrapper) + 1);
+ memcpy (concat_name, p, p_len);
+ concat_name[p_len] = '/';
+ strcpy (concat_name + p_len + 1, wrapper);
+ }
+ if (check_executable(concat_name))
+ return concat_name;
+ XFREE(concat_name);
+ }
+ }
+ /* not found in PATH; assume curdir */
+ }
+ /* Relative path | not found in path: prepend cwd */
+ if (getcwd (tmp, LT_PATHMAX) == NULL)
+ lt_fatal ("getcwd failed");
+ tmp_len = strlen(tmp);
+ concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1);
+ memcpy (concat_name, tmp, tmp_len);
+ concat_name[tmp_len] = '/';
+ strcpy (concat_name + tmp_len + 1, wrapper);
+
+ if (check_executable(concat_name))
+ return concat_name;
+ XFREE(concat_name);
+ return NULL;
+}
+
+char *
+strendzap(char *str, const char *pat)
+{
+ size_t len, patlen;
+
+ assert(str != NULL);
+ assert(pat != NULL);
+
+ len = strlen(str);
+ patlen = strlen(pat);
+
+ if (patlen <= len)
+ {
+ str += len - patlen;
+ if (strcmp(str, pat) == 0)
+ *str = '\0';
+ }
+ return str;
+}
+
+static void
+lt_error_core (int exit_status, const char * mode,
+ const char * message, va_list ap)
+{
+ fprintf (stderr, "%s: %s: ", program_name, mode);
+ vfprintf (stderr, message, ap);
+ fprintf (stderr, ".\n");
+
+ if (exit_status >= 0)
+ exit (exit_status);
+}
+
+void
+lt_fatal (const char *message, ...)
+{
+ va_list ap;
+ va_start (ap, message);
+ lt_error_core (EXIT_FAILURE, "FATAL", message, ap);
+ va_end (ap);
+}
+EOF
+ # we should really use a build-platform specific compiler
+ # here, but OTOH, the wrappers (shell script and this C one)
+ # are only useful if you want to execute the "real" binary.
+ # Since the "real" binary is built for $host, then this
+ # wrapper might as well be built for $host, too.
+ $run $LTCC $LTCFLAGS -s -o $cwrapper $cwrappersource
+ ;;
+ esac
+ $rm $output
+ trap "$rm $output; exit $EXIT_FAILURE" 1 2 15
+
+ $echo > $output "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='${SED} -e 1s/^X//'
+sed_quote_subst='$sed_quote_subst'
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+ # install mode needs the following variable:
+ notinst_deplibs='$notinst_deplibs'
+else
+ # When we are sourced in execute mode, \$file and \$echo are already set.
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ echo=\"$qecho\"
+ file=\"\$0\"
+ # Make sure echo works.
+ if test \"X\$1\" = X--no-reexec; then
+ # Discard the --no-reexec flag, and continue.
+ shift
+ elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then
+ # Yippee, \$echo works!
+ :
+ else
+ # Restart under the correct shell, and then maybe \$echo will work.
+ exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"}
+ fi
+ fi\
+"
+ $echo >> $output "\
+
+ # Find the directory that this script lives in.
+ thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\`
+ test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+ # Follow symbolic links until we get to the real thisdir.
+ file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\`
+ while test -n \"\$file\"; do
+ destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\`
+
+ # If there was a directory component, then change thisdir.
+ if test \"x\$destdir\" != \"x\$file\"; then
+ case \"\$destdir\" in
+ [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
+ *) thisdir=\"\$thisdir/\$destdir\" ;;
+ esac
+ fi
+
+ file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\`
+ file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\`
+ done
+
+ # Try to get the absolute directory name.
+ absdir=\`cd \"\$thisdir\" && pwd\`
+ test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+ if test "$fast_install" = yes; then
+ $echo >> $output "\
+ program=lt-'$outputname'$exeext
+ progdir=\"\$thisdir/$objdir\"
+
+ if test ! -f \"\$progdir/\$program\" || \\
+ { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\
+ test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+ file=\"\$\$-\$program\"
+
+ if test ! -d \"\$progdir\"; then
+ $mkdir \"\$progdir\"
+ else
+ $rm \"\$progdir/\$file\"
+ fi"
+
+ $echo >> $output "\
+
+ # relink executable if necessary
+ if test -n \"\$relink_command\"; then
+ if relink_command_output=\`eval \$relink_command 2>&1\`; then :
+ else
+ $echo \"\$relink_command_output\" >&2
+ $rm \"\$progdir/\$file\"
+ exit $EXIT_FAILURE
+ fi
+ fi
+
+ $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+ { $rm \"\$progdir/\$program\";
+ $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+ $rm \"\$progdir/\$file\"
+ fi"
+ else
+ $echo >> $output "\
+ program='$outputname'
+ progdir=\"\$thisdir/$objdir\"
+"
+ fi
+
+ $echo >> $output "\
+
+ if test -f \"\$progdir/\$program\"; then"
+
+ # Export our shlibpath_var if we have one.
+ if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+ $echo >> $output "\
+ # Add our own library path to $shlibpath_var
+ $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+ # Some systems cannot cope with colon-terminated $shlibpath_var
+ # The second colon is a workaround for a bug in BeOS R4 sed
+ $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\`
+
+ export $shlibpath_var
+"
+ fi
+
+ # fixup the dll searchpath if we need to.
+ if test -n "$dllsearchpath"; then
+ $echo >> $output "\
+ # Add the dll search path components to the executable PATH
+ PATH=$dllsearchpath:\$PATH
+"
+ fi
+
+ $echo >> $output "\
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ # Run the actual program with our arguments.
+"
+ case $host in
+ # Backslashes separate directories on plain windows
+ *-*-mingw | *-*-os2*)
+ $echo >> $output "\
+ exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
+"
+ ;;
+
+ *)
+ $echo >> $output "\
+ exec \"\$progdir/\$program\" \${1+\"\$@\"}
+"
+ ;;
+ esac
+ $echo >> $output "\
+ \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\"
+ exit $EXIT_FAILURE
+ fi
+ else
+ # The program doesn't exist.
+ \$echo \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2
+ \$echo \"This script is just a wrapper for \$program.\" 1>&2
+ $echo \"See the $PACKAGE documentation for more information.\" 1>&2
+ exit $EXIT_FAILURE
+ fi
+fi\
+"
+ chmod +x $output
+ fi
+ exit $EXIT_SUCCESS
+ ;;
+ esac
+
+ # See if we need to build an old-fashioned archive.
+ for oldlib in $oldlibs; do
+
+ if test "$build_libtool_libs" = convenience; then
+ oldobjs="$libobjs_save"
+ addlibs="$convenience"
+ build_libtool_libs=no
+ else
+ if test "$build_libtool_libs" = module; then
+ oldobjs="$libobjs_save"
+ build_libtool_libs=no
+ else
+ oldobjs="$old_deplibs $non_pic_objects"
+ fi
+ addlibs="$old_convenience"
+ fi
+
+ if test -n "$addlibs"; then
+ gentop="$output_objdir/${outputname}x"
+ generated="$generated $gentop"
+
+ func_extract_archives $gentop $addlibs
+ oldobjs="$oldobjs $func_extract_archives_result"
+ fi
+
+ # Do each command in the archive commands.
+ if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
+ cmds=$old_archive_from_new_cmds
+ else
+ # POSIX demands no paths to be encoded in archives. We have
+ # to avoid creating archives with duplicate basenames if we
+ # might have to extract them afterwards, e.g., when creating a
+ # static archive out of a convenience library, or when linking
+ # the entirety of a libtool archive into another (currently
+ # not supported by libtool).
+ if (for obj in $oldobjs
+ do
+ $echo "X$obj" | $Xsed -e 's%^.*/%%'
+ done | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ $echo "copying selected object files to avoid basename conflicts..."
+
+ if test -z "$gentop"; then
+ gentop="$output_objdir/${outputname}x"
+ generated="$generated $gentop"
+
+ $show "${rm}r $gentop"
+ $run ${rm}r "$gentop"
+ $show "$mkdir $gentop"
+ $run $mkdir "$gentop"
+ exit_status=$?
+ if test "$exit_status" -ne 0 && test ! -d "$gentop"; then
+ exit $exit_status
+ fi
+ fi
+
+ save_oldobjs=$oldobjs
+ oldobjs=
+ counter=1
+ for obj in $save_oldobjs
+ do
+ objbase=`$echo "X$obj" | $Xsed -e 's%^.*/%%'`
+ case " $oldobjs " in
+ " ") oldobjs=$obj ;;
+ *[\ /]"$objbase "*)
+ while :; do
+ # Make sure we don't pick an alternate name that also
+ # overlaps.
+ newobj=lt$counter-$objbase
+ counter=`expr $counter + 1`
+ case " $oldobjs " in
+ *[\ /]"$newobj "*) ;;
+ *) if test ! -f "$gentop/$newobj"; then break; fi ;;
+ esac
+ done
+ $show "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj"
+ $run ln "$obj" "$gentop/$newobj" ||
+ $run cp "$obj" "$gentop/$newobj"
+ oldobjs="$oldobjs $gentop/$newobj"
+ ;;
+ *) oldobjs="$oldobjs $obj" ;;
+ esac
+ done
+ fi
+
+ eval cmds=\"$old_archive_cmds\"
+
+ if len=`expr "X$cmds" : ".*"` &&
+ test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ cmds=$old_archive_cmds
+ else
+ # the command line is too long to link in one step, link in parts
+ $echo "using piecewise archive linking..."
+ save_RANLIB=$RANLIB
+ RANLIB=:
+ objlist=
+ concat_cmds=
+ save_oldobjs=$oldobjs
+
+ # Is there a better way of finding the last object in the list?
+ for obj in $save_oldobjs
+ do
+ last_oldobj=$obj
+ done
+ for obj in $save_oldobjs
+ do
+ oldobjs="$objlist $obj"
+ objlist="$objlist $obj"
+ eval test_cmds=\"$old_archive_cmds\"
+ if len=`expr "X$test_cmds" : ".*" 2>/dev/null` &&
+ test "$len" -le "$max_cmd_len"; then
+ :
+ else
+ # the above command should be used before it gets too long
+ oldobjs=$objlist
+ if test "$obj" = "$last_oldobj" ; then
+ RANLIB=$save_RANLIB
+ fi
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\"
+ objlist=
+ fi
+ done
+ RANLIB=$save_RANLIB
+ oldobjs=$objlist
+ if test "X$oldobjs" = "X" ; then
+ eval cmds=\"\$concat_cmds\"
+ else
+ eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
+ fi
+ fi
+ fi
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ eval cmd=\"$cmd\"
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ done
+
+ if test -n "$generated"; then
+ $show "${rm}r$generated"
+ $run ${rm}r$generated
+ fi
+
+ # Now create the libtool archive.
+ case $output in
+ *.la)
+ old_library=
+ test "$build_old_libs" = yes && old_library="$libname.$libext"
+ $show "creating $output"
+
+ # Preserve any variables that may affect compiler behavior
+ for var in $variables_saved_for_relink; do
+ if eval test -z \"\${$var+set}\"; then
+ relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command"
+ elif eval var_value=\$$var; test -z "$var_value"; then
+ relink_command="$var=; export $var; $relink_command"
+ else
+ var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"`
+ relink_command="$var=\"$var_value\"; export $var; $relink_command"
+ fi
+ done
+ # Quote the link command for shipping.
+ relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+ relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"`
+ if test "$hardcode_automatic" = yes ; then
+ relink_command=
+ fi
+
+
+ # Only create the output if not a dry run.
+ if test -z "$run"; then
+ for installed in no yes; do
+ if test "$installed" = yes; then
+ if test -z "$install_libdir"; then
+ break
+ fi
+ output="$output_objdir/$outputname"i
+ # Replace all uninstalled libtool libraries with the installed ones
+ newdependency_libs=
+ for deplib in $dependency_libs; do
+ case $deplib in
+ *.la)
+ name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'`
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+ if test -z "$libdir"; then
+ $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ newdependency_libs="$newdependency_libs $libdir/$name"
+ ;;
+ *) newdependency_libs="$newdependency_libs $deplib" ;;
+ esac
+ done
+ dependency_libs="$newdependency_libs"
+ newdlfiles=
+ for lib in $dlfiles; do
+ name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ if test -z "$libdir"; then
+ $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ newdlfiles="$newdlfiles $libdir/$name"
+ done
+ dlfiles="$newdlfiles"
+ newdlprefiles=
+ for lib in $dlprefiles; do
+ name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ if test -z "$libdir"; then
+ $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ newdlprefiles="$newdlprefiles $libdir/$name"
+ done
+ dlprefiles="$newdlprefiles"
+ else
+ newdlfiles=
+ for lib in $dlfiles; do
+ case $lib in
+ [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+ *) abs=`pwd`"/$lib" ;;
+ esac
+ newdlfiles="$newdlfiles $abs"
+ done
+ dlfiles="$newdlfiles"
+ newdlprefiles=
+ for lib in $dlprefiles; do
+ case $lib in
+ [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+ *) abs=`pwd`"/$lib" ;;
+ esac
+ newdlprefiles="$newdlprefiles $abs"
+ done
+ dlprefiles="$newdlprefiles"
+ fi
+ $rm $output
+ # place dlname in correct position for cygwin
+ tdlname=$dlname
+ case $host,$output,$installed,$module,$dlname in
+ *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;;
+ esac
+ $echo > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$tdlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=$module
+
+# Files to dlopen/dlpreopen
+dlopen='$dlfiles'
+dlpreopen='$dlprefiles'
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'"
+ if test "$installed" = no && test "$need_relink" = yes; then
+ $echo >> $output "\
+relink_command=\"$relink_command\""
+ fi
+ done
+ fi
+
+ # Do a symbolic link so that the libtool archive can be found in
+ # LD_LIBRARY_PATH before the program is installed.
+ $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)"
+ $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $?
+ ;;
+ esac
+ exit $EXIT_SUCCESS
+ ;;
+
+ # libtool install mode
+ install)
+ modename="$modename: install"
+
+ # There may be an optional sh(1) argument at the beginning of
+ # install_prog (especially on Windows NT).
+ if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
+ # Allow the use of GNU shtool's install command.
+ $echo "X$nonopt" | grep shtool > /dev/null; then
+ # Aesthetically quote it.
+ arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ install_prog="$arg "
+ arg="$1"
+ shift
+ else
+ install_prog=
+ arg=$nonopt
+ fi
+
+ # The real first argument should be the name of the installation program.
+ # Aesthetically quote it.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ install_prog="$install_prog$arg"
+
+ # We need to accept at least all the BSD install flags.
+ dest=
+ files=
+ opts=
+ prev=
+ install_type=
+ isdir=no
+ stripme=
+ for arg
+ do
+ if test -n "$dest"; then
+ files="$files $dest"
+ dest=$arg
+ continue
+ fi
+
+ case $arg in
+ -d) isdir=yes ;;
+ -f)
+ case " $install_prog " in
+ *[\\\ /]cp\ *) ;;
+ *) prev=$arg ;;
+ esac
+ ;;
+ -g | -m | -o) prev=$arg ;;
+ -s)
+ stripme=" -s"
+ continue
+ ;;
+ -*)
+ ;;
+ *)
+ # If the previous option needed an argument, then skip it.
+ if test -n "$prev"; then
+ prev=
+ else
+ dest=$arg
+ continue
+ fi
+ ;;
+ esac
+
+ # Aesthetically quote the argument.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ install_prog="$install_prog $arg"
+ done
+
+ if test -z "$install_prog"; then
+ $echo "$modename: you must specify an install program" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ if test -n "$prev"; then
+ $echo "$modename: the \`$prev' option requires an argument" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ if test -z "$files"; then
+ if test -z "$dest"; then
+ $echo "$modename: no file or destination specified" 1>&2
+ else
+ $echo "$modename: you must specify a destination" 1>&2
+ fi
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Strip any trailing slash from the destination.
+ dest=`$echo "X$dest" | $Xsed -e 's%/$%%'`
+
+ # Check to see that the destination is a directory.
+ test -d "$dest" && isdir=yes
+ if test "$isdir" = yes; then
+ destdir="$dest"
+ destname=
+ else
+ destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$destdir" = "X$dest" && destdir=.
+ destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'`
+
+ # Not a directory, so check to see that there is only one file specified.
+ set dummy $files
+ if test "$#" -gt 2; then
+ $echo "$modename: \`$dest' is not a directory" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ fi
+ case $destdir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ for file in $files; do
+ case $file in
+ *.lo) ;;
+ *)
+ $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+ done
+ ;;
+ esac
+
+ # This variable tells wrapper scripts just to set variables rather
+ # than running their programs.
+ libtool_install_magic="$magic"
+
+ staticlibs=
+ future_libdirs=
+ current_libdirs=
+ for file in $files; do
+
+ # Do each installation.
+ case $file in
+ *.$libext)
+ # Do the static libraries later.
+ staticlibs="$staticlibs $file"
+ ;;
+
+ *.la)
+ # Check to see that this really is a libtool archive.
+ if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+ else
+ $echo "$modename: \`$file' is not a valid libtool archive" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ library_names=
+ old_library=
+ relink_command=
+ # If there is no directory component, then add one.
+ case $file in
+ */* | *\\*) . $file ;;
+ *) . ./$file ;;
+ esac
+
+ # Add the libdir to current_libdirs if it is the destination.
+ if test "X$destdir" = "X$libdir"; then
+ case "$current_libdirs " in
+ *" $libdir "*) ;;
+ *) current_libdirs="$current_libdirs $libdir" ;;
+ esac
+ else
+ # Note the libdir as a future libdir.
+ case "$future_libdirs " in
+ *" $libdir "*) ;;
+ *) future_libdirs="$future_libdirs $libdir" ;;
+ esac
+ fi
+
+ dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/
+ test "X$dir" = "X$file/" && dir=
+ dir="$dir$objdir"
+
+ if test -n "$relink_command"; then
+ # Determine the prefix the user has applied to our future dir.
+ inst_prefix_dir=`$echo "$destdir" | $SED "s%$libdir\$%%"`
+
+ # Don't allow the user to place us outside of our expected
+ # location b/c this prevents finding dependent libraries that
+ # are installed to the same prefix.
+ # At present, this check doesn't affect windows .dll's that
+ # are installed into $libdir/../bin (currently, that works fine)
+ # but it's something to keep an eye on.
+ if test "$inst_prefix_dir" = "$destdir"; then
+ $echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ if test -n "$inst_prefix_dir"; then
+ # Stick the inst_prefix_dir data into the link command.
+ relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
+ else
+ relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
+ fi
+
+ $echo "$modename: warning: relinking \`$file'" 1>&2
+ $show "$relink_command"
+ if $run eval "$relink_command"; then :
+ else
+ $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ fi
+
+ # See the names of the shared library.
+ set dummy $library_names
+ if test -n "$2"; then
+ realname="$2"
+ shift
+ shift
+
+ srcname="$realname"
+ test -n "$relink_command" && srcname="$realname"T
+
+ # Install the shared library and build the symlinks.
+ $show "$install_prog $dir/$srcname $destdir/$realname"
+ $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $?
+ if test -n "$stripme" && test -n "$striplib"; then
+ $show "$striplib $destdir/$realname"
+ $run eval "$striplib $destdir/$realname" || exit $?
+ fi
+
+ if test "$#" -gt 0; then
+ # Delete the old symlinks, and create new ones.
+ # Try `ln -sf' first, because the `ln' binary might depend on
+ # the symlink we replace! Solaris /bin/ln does not understand -f,
+ # so we also need to try rm && ln -s.
+ for linkname
+ do
+ if test "$linkname" != "$realname"; then
+ $show "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })"
+ $run eval "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })"
+ fi
+ done
+ fi
+
+ # Do each command in the postinstall commands.
+ lib="$destdir/$realname"
+ cmds=$postinstall_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || {
+ lt_exit=$?
+
+ # Restore the uninstalled library and exit
+ if test "$mode" = relink; then
+ $run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)'
+ fi
+
+ exit $lt_exit
+ }
+ done
+ IFS="$save_ifs"
+ fi
+
+ # Install the pseudo-library for information purposes.
+ name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+ instname="$dir/$name"i
+ $show "$install_prog $instname $destdir/$name"
+ $run eval "$install_prog $instname $destdir/$name" || exit $?
+
+ # Maybe install the static library, too.
+ test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library"
+ ;;
+
+ *.lo)
+ # Install (i.e. copy) a libtool object.
+
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile="$destdir/$destname"
+ else
+ destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+ destfile="$destdir/$destfile"
+ fi
+
+ # Deduce the name of the destination old-style object file.
+ case $destfile in
+ *.lo)
+ staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"`
+ ;;
+ *.$objext)
+ staticdest="$destfile"
+ destfile=
+ ;;
+ *)
+ $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+
+ # Install the libtool object if requested.
+ if test -n "$destfile"; then
+ $show "$install_prog $file $destfile"
+ $run eval "$install_prog $file $destfile" || exit $?
+ fi
+
+ # Install the old object if enabled.
+ if test "$build_old_libs" = yes; then
+ # Deduce the name of the old-style object file.
+ staticobj=`$echo "X$file" | $Xsed -e "$lo2o"`
+
+ $show "$install_prog $staticobj $staticdest"
+ $run eval "$install_prog \$staticobj \$staticdest" || exit $?
+ fi
+ exit $EXIT_SUCCESS
+ ;;
+
+ *)
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile="$destdir/$destname"
+ else
+ destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+ destfile="$destdir/$destfile"
+ fi
+
+ # If the file is missing, and there is a .exe on the end, strip it
+ # because it is most likely a libtool script we actually want to
+ # install
+ stripped_ext=""
+ case $file in
+ *.exe)
+ if test ! -f "$file"; then
+ file=`$echo $file|${SED} 's,.exe$,,'`
+ stripped_ext=".exe"
+ fi
+ ;;
+ esac
+
+ # Do a test to see if this is really a libtool program.
+ case $host in
+ *cygwin*|*mingw*)
+ wrapper=`$echo $file | ${SED} -e 's,.exe$,,'`
+ ;;
+ *)
+ wrapper=$file
+ ;;
+ esac
+ if (${SED} -e '4q' $wrapper | grep "^# Generated by .*$PACKAGE")>/dev/null 2>&1; then
+ notinst_deplibs=
+ relink_command=
+
+ # Note that it is not necessary on cygwin/mingw to append a dot to
+ # foo even if both foo and FILE.exe exist: automatic-append-.exe
+ # behavior happens only for exec(3), not for open(2)! Also, sourcing
+ # `FILE.' does not work on cygwin managed mounts.
+ #
+ # If there is no directory component, then add one.
+ case $wrapper in
+ */* | *\\*) . ${wrapper} ;;
+ *) . ./${wrapper} ;;
+ esac
+
+ # Check the variables that should have been set.
+ if test -z "$notinst_deplibs"; then
+ $echo "$modename: invalid libtool wrapper script \`$wrapper'" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ finalize=yes
+ for lib in $notinst_deplibs; do
+ # Check to see that each library is installed.
+ libdir=
+ if test -f "$lib"; then
+ # If there is no directory component, then add one.
+ case $lib in
+ */* | *\\*) . $lib ;;
+ *) . ./$lib ;;
+ esac
+ fi
+ libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test
+ if test -n "$libdir" && test ! -f "$libfile"; then
+ $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2
+ finalize=no
+ fi
+ done
+
+ relink_command=
+ # Note that it is not necessary on cygwin/mingw to append a dot to
+ # foo even if both foo and FILE.exe exist: automatic-append-.exe
+ # behavior happens only for exec(3), not for open(2)! Also, sourcing
+ # `FILE.' does not work on cygwin managed mounts.
+ #
+ # If there is no directory component, then add one.
+ case $wrapper in
+ */* | *\\*) . ${wrapper} ;;
+ *) . ./${wrapper} ;;
+ esac
+
+ outputname=
+ if test "$fast_install" = no && test -n "$relink_command"; then
+ if test "$finalize" = yes && test -z "$run"; then
+ tmpdir=`func_mktempdir`
+ file=`$echo "X$file$stripped_ext" | $Xsed -e 's%^.*/%%'`
+ outputname="$tmpdir/$file"
+ # Replace the output file specification.
+ relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'`
+
+ $show "$relink_command"
+ if $run eval "$relink_command"; then :
+ else
+ $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
+ ${rm}r "$tmpdir"
+ continue
+ fi
+ file="$outputname"
+ else
+ $echo "$modename: warning: cannot relink \`$file'" 1>&2
+ fi
+ else
+ # Install the binary that we compiled earlier.
+ file=`$echo "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"`
+ fi
+ fi
+
+ # remove .exe since cygwin /usr/bin/install will append another
+ # one anyway
+ case $install_prog,$host in
+ */usr/bin/install*,*cygwin*)
+ case $file:$destfile in
+ *.exe:*.exe)
+ # this is ok
+ ;;
+ *.exe:*)
+ destfile=$destfile.exe
+ ;;
+ *:*.exe)
+ destfile=`$echo $destfile | ${SED} -e 's,.exe$,,'`
+ ;;
+ esac
+ ;;
+ esac
+ $show "$install_prog$stripme $file $destfile"
+ $run eval "$install_prog\$stripme \$file \$destfile" || exit $?
+ test -n "$outputname" && ${rm}r "$tmpdir"
+ ;;
+ esac
+ done
+
+ for file in $staticlibs; do
+ name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+
+ # Set up the ranlib parameters.
+ oldlib="$destdir/$name"
+
+ $show "$install_prog $file $oldlib"
+ $run eval "$install_prog \$file \$oldlib" || exit $?
+
+ if test -n "$stripme" && test -n "$old_striplib"; then
+ $show "$old_striplib $oldlib"
+ $run eval "$old_striplib $oldlib" || exit $?
+ fi
+
+ # Do each command in the postinstall commands.
+ cmds=$old_postinstall_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ done
+
+ if test -n "$future_libdirs"; then
+ $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2
+ fi
+
+ if test -n "$current_libdirs"; then
+ # Maybe just do a dry run.
+ test -n "$run" && current_libdirs=" -n$current_libdirs"
+ exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs'
+ else
+ exit $EXIT_SUCCESS
+ fi
+ ;;
+
+ # libtool finish mode
+ finish)
+ modename="$modename: finish"
+ libdirs="$nonopt"
+ admincmds=
+
+ if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+ for dir
+ do
+ libdirs="$libdirs $dir"
+ done
+
+ for libdir in $libdirs; do
+ if test -n "$finish_cmds"; then
+ # Do each command in the finish commands.
+ cmds=$finish_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || admincmds="$admincmds
+ $cmd"
+ done
+ IFS="$save_ifs"
+ fi
+ if test -n "$finish_eval"; then
+ # Do the single finish_eval.
+ eval cmds=\"$finish_eval\"
+ $run eval "$cmds" || admincmds="$admincmds
+ $cmds"
+ fi
+ done
+ fi
+
+ # Exit here if they wanted silent mode.
+ test "$show" = : && exit $EXIT_SUCCESS
+
+ $echo "X----------------------------------------------------------------------" | $Xsed
+ $echo "Libraries have been installed in:"
+ for libdir in $libdirs; do
+ $echo " $libdir"
+ done
+ $echo
+ $echo "If you ever happen to want to link against installed libraries"
+ $echo "in a given directory, LIBDIR, you must either use libtool, and"
+ $echo "specify the full pathname of the library, or use the \`-LLIBDIR'"
+ $echo "flag during linking and do at least one of the following:"
+ if test -n "$shlibpath_var"; then
+ $echo " - add LIBDIR to the \`$shlibpath_var' environment variable"
+ $echo " during execution"
+ fi
+ if test -n "$runpath_var"; then
+ $echo " - add LIBDIR to the \`$runpath_var' environment variable"
+ $echo " during linking"
+ fi
+ if test -n "$hardcode_libdir_flag_spec"; then
+ libdir=LIBDIR
+ eval flag=\"$hardcode_libdir_flag_spec\"
+
+ $echo " - use the \`$flag' linker flag"
+ fi
+ if test -n "$admincmds"; then
+ $echo " - have your system administrator run these commands:$admincmds"
+ fi
+ if test -f /etc/ld.so.conf; then
+ $echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
+ fi
+ $echo
+ $echo "See any operating system documentation about shared libraries for"
+ $echo "more information, such as the ld(1) and ld.so(8) manual pages."
+ $echo "X----------------------------------------------------------------------" | $Xsed
+ exit $EXIT_SUCCESS
+ ;;
+
+ # libtool execute mode
+ execute)
+ modename="$modename: execute"
+
+ # The first argument is the command name.
+ cmd="$nonopt"
+ if test -z "$cmd"; then
+ $echo "$modename: you must specify a COMMAND" 1>&2
+ $echo "$help"
+ exit $EXIT_FAILURE
+ fi
+
+ # Handle -dlopen flags immediately.
+ for file in $execute_dlfiles; do
+ if test ! -f "$file"; then
+ $echo "$modename: \`$file' is not a file" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ dir=
+ case $file in
+ *.la)
+ # Check to see that this really is a libtool archive.
+ if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+ else
+ $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Read the libtool library.
+ dlname=
+ library_names=
+
+ # If there is no directory component, then add one.
+ case $file in
+ */* | *\\*) . $file ;;
+ *) . ./$file ;;
+ esac
+
+ # Skip this library if it cannot be dlopened.
+ if test -z "$dlname"; then
+ # Warn if it was a shared library.
+ test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'"
+ continue
+ fi
+
+ dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$dir" = "X$file" && dir=.
+
+ if test -f "$dir/$objdir/$dlname"; then
+ dir="$dir/$objdir"
+ else
+ $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ ;;
+
+ *.lo)
+ # Just add the directory containing the .lo file.
+ dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$dir" = "X$file" && dir=.
+ ;;
+
+ *)
+ $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2
+ continue
+ ;;
+ esac
+
+ # Get the absolute pathname.
+ absdir=`cd "$dir" && pwd`
+ test -n "$absdir" && dir="$absdir"
+
+ # Now add the directory to shlibpath_var.
+ if eval "test -z \"\$$shlibpath_var\""; then
+ eval "$shlibpath_var=\"\$dir\""
+ else
+ eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+ fi
+ done
+
+ # This variable tells wrapper scripts just to set shlibpath_var
+ # rather than running their programs.
+ libtool_execute_magic="$magic"
+
+ # Check if any of the arguments is a wrapper script.
+ args=
+ for file
+ do
+ case $file in
+ -*) ;;
+ *)
+ # Do a test to see if this is really a libtool program.
+ if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ # If there is no directory component, then add one.
+ case $file in
+ */* | *\\*) . $file ;;
+ *) . ./$file ;;
+ esac
+
+ # Transform arg to wrapped name.
+ file="$progdir/$program"
+ fi
+ ;;
+ esac
+ # Quote arguments (to preserve shell metacharacters).
+ file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"`
+ args="$args \"$file\""
+ done
+
+ if test -z "$run"; then
+ if test -n "$shlibpath_var"; then
+ # Export the shlibpath_var.
+ eval "export $shlibpath_var"
+ fi
+
+ # Restore saved environment variables
+ if test "${save_LC_ALL+set}" = set; then
+ LC_ALL="$save_LC_ALL"; export LC_ALL
+ fi
+ if test "${save_LANG+set}" = set; then
+ LANG="$save_LANG"; export LANG
+ fi
+
+ # Now prepare to actually exec the command.
+ exec_cmd="\$cmd$args"
+ else
+ # Display what would be done.
+ if test -n "$shlibpath_var"; then
+ eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\""
+ $echo "export $shlibpath_var"
+ fi
+ $echo "$cmd$args"
+ exit $EXIT_SUCCESS
+ fi
+ ;;
+
+ # libtool clean and uninstall mode
+ clean | uninstall)
+ modename="$modename: $mode"
+ rm="$nonopt"
+ files=
+ rmforce=
+ exit_status=0
+
+ # This variable tells wrapper scripts just to set variables rather
+ # than running their programs.
+ libtool_install_magic="$magic"
+
+ for arg
+ do
+ case $arg in
+ -f) rm="$rm $arg"; rmforce=yes ;;
+ -*) rm="$rm $arg" ;;
+ *) files="$files $arg" ;;
+ esac
+ done
+
+ if test -z "$rm"; then
+ $echo "$modename: you must specify an RM program" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ rmdirs=
+
+ origobjdir="$objdir"
+ for file in $files; do
+ dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$dir" = "X$file"; then
+ dir=.
+ objdir="$origobjdir"
+ else
+ objdir="$dir/$origobjdir"
+ fi
+ name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+ test "$mode" = uninstall && objdir="$dir"
+
+ # Remember objdir for removal later, being careful to avoid duplicates
+ if test "$mode" = clean; then
+ case " $rmdirs " in
+ *" $objdir "*) ;;
+ *) rmdirs="$rmdirs $objdir" ;;
+ esac
+ fi
+
+ # Don't error if the file doesn't exist and rm -f was used.
+ if (test -L "$file") >/dev/null 2>&1 \
+ || (test -h "$file") >/dev/null 2>&1 \
+ || test -f "$file"; then
+ :
+ elif test -d "$file"; then
+ exit_status=1
+ continue
+ elif test "$rmforce" = yes; then
+ continue
+ fi
+
+ rmfiles="$file"
+
+ case $name in
+ *.la)
+ # Possibly a libtool archive, so verify it.
+ if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ . $dir/$name
+
+ # Delete the libtool libraries and symlinks.
+ for n in $library_names; do
+ rmfiles="$rmfiles $objdir/$n"
+ done
+ test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library"
+
+ case "$mode" in
+ clean)
+ case " $library_names " in
+ # " " in the beginning catches empty $dlname
+ *" $dlname "*) ;;
+ *) rmfiles="$rmfiles $objdir/$dlname" ;;
+ esac
+ test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i"
+ ;;
+ uninstall)
+ if test -n "$library_names"; then
+ # Do each command in the postuninstall commands.
+ cmds=$postuninstall_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd"
+ if test "$?" -ne 0 && test "$rmforce" != yes; then
+ exit_status=1
+ fi
+ done
+ IFS="$save_ifs"
+ fi
+
+ if test -n "$old_library"; then
+ # Do each command in the old_postuninstall commands.
+ cmds=$old_postuninstall_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd"
+ if test "$?" -ne 0 && test "$rmforce" != yes; then
+ exit_status=1
+ fi
+ done
+ IFS="$save_ifs"
+ fi
+ # FIXME: should reinstall the best remaining shared library.
+ ;;
+ esac
+ fi
+ ;;
+
+ *.lo)
+ # Possibly a libtool object, so verify it.
+ if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+
+ # Read the .lo file
+ . $dir/$name
+
+ # Add PIC object to the list of files to remove.
+ if test -n "$pic_object" \
+ && test "$pic_object" != none; then
+ rmfiles="$rmfiles $dir/$pic_object"
+ fi
+
+ # Add non-PIC object to the list of files to remove.
+ if test -n "$non_pic_object" \
+ && test "$non_pic_object" != none; then
+ rmfiles="$rmfiles $dir/$non_pic_object"
+ fi
+ fi
+ ;;
+
+ *)
+ if test "$mode" = clean ; then
+ noexename=$name
+ case $file in
+ *.exe)
+ file=`$echo $file|${SED} 's,.exe$,,'`
+ noexename=`$echo $name|${SED} 's,.exe$,,'`
+ # $file with .exe has already been added to rmfiles,
+ # add $file without .exe
+ rmfiles="$rmfiles $file"
+ ;;
+ esac
+ # Do a test to see if this is a libtool program.
+ if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ relink_command=
+ . $dir/$noexename
+
+ # note $name still contains .exe if it was in $file originally
+ # as does the version of $file that was added into $rmfiles
+ rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}"
+ if test "$fast_install" = yes && test -n "$relink_command"; then
+ rmfiles="$rmfiles $objdir/lt-$name"
+ fi
+ if test "X$noexename" != "X$name" ; then
+ rmfiles="$rmfiles $objdir/lt-${noexename}.c"
+ fi
+ fi
+ fi
+ ;;
+ esac
+ $show "$rm $rmfiles"
+ $run $rm $rmfiles || exit_status=1
+ done
+ objdir="$origobjdir"
+
+ # Try to remove the ${objdir}s in the directories where we deleted files
+ for dir in $rmdirs; do
+ if test -d "$dir"; then
+ $show "rmdir $dir"
+ $run rmdir $dir >/dev/null 2>&1
+ fi
+ done
+
+ exit $exit_status
+ ;;
+
+ "")
+ $echo "$modename: you must specify a MODE" 1>&2
+ $echo "$generic_help" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+
+ if test -z "$exec_cmd"; then
+ $echo "$modename: invalid operation mode \`$mode'" 1>&2
+ $echo "$generic_help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+fi # test -z "$show_help"
+
+if test -n "$exec_cmd"; then
+ eval exec $exec_cmd
+ exit $EXIT_FAILURE
+fi
+
+# We need to display help for each of the modes.
+case $mode in
+"") $echo \
+"Usage: $modename [OPTION]... [MODE-ARG]...
+
+Provide generalized library-building support services.
+
+ --config show all configuration variables
+ --debug enable verbose shell tracing
+-n, --dry-run display commands without modifying any files
+ --features display basic configuration information and exit
+ --finish same as \`--mode=finish'
+ --help display this help message and exit
+ --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS]
+ --quiet same as \`--silent'
+ --silent don't print informational messages
+ --tag=TAG use configuration variables from tag TAG
+ --version print version information
+
+MODE must be one of the following:
+
+ clean remove files from the build directory
+ compile compile a source file into a libtool object
+ execute automatically set library path, then run a program
+ finish complete the installation of libtool libraries
+ install install libraries or executables
+ link create a library or an executable
+ uninstall remove libraries from an installed directory
+
+MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for
+a more detailed description of MODE.
+
+Report bugs to <bug-libtool@gnu.org>."
+ exit $EXIT_SUCCESS
+ ;;
+
+clean)
+ $echo \
+"Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
+
+Remove files from the build directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, object or program, all the files associated
+with it are deleted. Otherwise, only FILE itself is deleted using RM."
+ ;;
+
+compile)
+ $echo \
+"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+ -o OUTPUT-FILE set the output file name to OUTPUT-FILE
+ -prefer-pic try to building PIC objects only
+ -prefer-non-pic try to building non-PIC objects only
+ -static always build a \`.o' file suitable for static linking
+
+COMPILE-COMMAND is a command to be used in creating a \`standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix \`.c' with the
+library object suffix, \`.lo'."
+ ;;
+
+execute)
+ $echo \
+"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+ -dlopen FILE add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to \`-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+ ;;
+
+finish)
+ $echo \
+"Usage: $modename [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges. Use
+the \`--dry-run' option if you just want to see what would be executed."
+ ;;
+
+install)
+ $echo \
+"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command. The first component should be
+either the \`install' or \`cp' program.
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+ ;;
+
+link)
+ $echo \
+"Usage: $modename [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+ -all-static do not do any dynamic linking at all
+ -avoid-version do not add a version suffix if possible
+ -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime
+ -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols
+ -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+ -export-symbols SYMFILE
+ try to export only the symbols listed in SYMFILE
+ -export-symbols-regex REGEX
+ try to export only the symbols matching REGEX
+ -LLIBDIR search LIBDIR for required installed libraries
+ -lNAME OUTPUT-FILE requires the installed library libNAME
+ -module build a library that can dlopened
+ -no-fast-install disable the fast-install mode
+ -no-install link a not-installable executable
+ -no-undefined declare that a library does not refer to external symbols
+ -o OUTPUT-FILE create OUTPUT-FILE from the specified objects
+ -objectlist FILE Use a list of object files found in FILE to specify objects
+ -precious-files-regex REGEX
+ don't remove output files matching REGEX
+ -release RELEASE specify package release information
+ -rpath LIBDIR the created library will eventually be installed in LIBDIR
+ -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries
+ -static do not do any dynamic linking of libtool libraries
+ -version-info CURRENT[:REVISION[:AGE]]
+ specify library version info [each variable defaults to 0]
+
+All other options (arguments beginning with \`-') are ignored.
+
+Every other argument is treated as a filename. Files ending in \`.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
+only library objects (\`.lo' files) may be specified, and \`-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
+using \`ar' and \`ranlib', or on Windows using \`lib'.
+
+If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
+is created, otherwise an executable program is created."
+ ;;
+
+uninstall)
+ $echo \
+"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+ ;;
+
+*)
+ $echo "$modename: invalid operation mode \`$mode'" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+esac
+
+$echo
+$echo "Try \`$modename --help' for more information about other modes."
+
+exit $?
+
+# The TAGs below are defined such that we never get into a situation
+# in which we disable both kinds of libraries. Given conflicting
+# choices, we go for a static library, that is the most portable,
+# since we can't tell whether shared libraries were disabled because
+# the user asked for that or because the platform doesn't support
+# them. This is particularly important on AIX, because we don't
+# support having both static and shared libraries enabled at the same
+# time on that platform, so we default to a shared-only configuration.
+# If a disable-shared tag is given, we'll fallback to a static-only
+# configuration. But we'll never go from static-only to shared-only.
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
+disable_libs=shared
+# ### END LIBTOOL TAG CONFIG: disable-shared
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-static
+disable_libs=static
+# ### END LIBTOOL TAG CONFIG: disable-static
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
diff --git a/qpid/cpp/build-aux/mdate-sh b/qpid/cpp/build-aux/mdate-sh
new file mode 100755
index 0000000000..cd916c0a34
--- /dev/null
+++ b/qpid/cpp/build-aux/mdate-sh
@@ -0,0 +1,201 @@
+#!/bin/sh
+# Get modification time of a file or directory and pretty-print it.
+
+scriptversion=2005-06-29.22
+
+# Copyright (C) 1995, 1996, 1997, 2003, 2004, 2005 Free Software
+# Foundation, Inc.
+# written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, June 1995
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+case $1 in
+ '')
+ echo "$0: No file. Try \`$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: mdate-sh [--help] [--version] FILE
+
+Pretty-print the modification time of FILE.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "mdate-sh $scriptversion"
+ exit $?
+ ;;
+esac
+
+# Prevent date giving response in another language.
+LANG=C
+export LANG
+LC_ALL=C
+export LC_ALL
+LC_TIME=C
+export LC_TIME
+
+# GNU ls changes its time format in response to the TIME_STYLE
+# variable. Since we cannot assume `unset' works, revert this
+# variable to its documented default.
+if test "${TIME_STYLE+set}" = set; then
+ TIME_STYLE=posix-long-iso
+ export TIME_STYLE
+fi
+
+save_arg1=$1
+
+# Find out how to get the extended ls output of a file or directory.
+if ls -L /dev/null 1>/dev/null 2>&1; then
+ ls_command='ls -L -l -d'
+else
+ ls_command='ls -l -d'
+fi
+
+# A `ls -l' line looks as follows on OS/2.
+# drwxrwx--- 0 Aug 11 2001 foo
+# This differs from Unix, which adds ownership information.
+# drwxrwx--- 2 root root 4096 Aug 11 2001 foo
+#
+# To find the date, we split the line on spaces and iterate on words
+# until we find a month. This cannot work with files whose owner is a
+# user named `Jan', or `Feb', etc. However, it's unlikely that `/'
+# will be owned by a user whose name is a month. So we first look at
+# the extended ls output of the root directory to decide how many
+# words should be skipped to get the date.
+
+# On HPUX /bin/sh, "set" interprets "-rw-r--r--" as options, so the "x" below.
+set x`ls -l -d /`
+
+# Find which argument is the month.
+month=
+command=
+until test $month
+do
+ shift
+ # Add another shift to the command.
+ command="$command shift;"
+ case $1 in
+ Jan) month=January; nummonth=1;;
+ Feb) month=February; nummonth=2;;
+ Mar) month=March; nummonth=3;;
+ Apr) month=April; nummonth=4;;
+ May) month=May; nummonth=5;;
+ Jun) month=June; nummonth=6;;
+ Jul) month=July; nummonth=7;;
+ Aug) month=August; nummonth=8;;
+ Sep) month=September; nummonth=9;;
+ Oct) month=October; nummonth=10;;
+ Nov) month=November; nummonth=11;;
+ Dec) month=December; nummonth=12;;
+ esac
+done
+
+# Get the extended ls output of the file or directory.
+set dummy x`eval "$ls_command \"\$save_arg1\""`
+
+# Remove all preceding arguments
+eval $command
+
+# Because of the dummy argument above, month is in $2.
+#
+# On a POSIX system, we should have
+#
+# $# = 5
+# $1 = file size
+# $2 = month
+# $3 = day
+# $4 = year or time
+# $5 = filename
+#
+# On Darwin 7.7.0 and 7.6.0, we have
+#
+# $# = 4
+# $1 = day
+# $2 = month
+# $3 = year or time
+# $4 = filename
+
+# Get the month.
+case $2 in
+ Jan) month=January; nummonth=1;;
+ Feb) month=February; nummonth=2;;
+ Mar) month=March; nummonth=3;;
+ Apr) month=April; nummonth=4;;
+ May) month=May; nummonth=5;;
+ Jun) month=June; nummonth=6;;
+ Jul) month=July; nummonth=7;;
+ Aug) month=August; nummonth=8;;
+ Sep) month=September; nummonth=9;;
+ Oct) month=October; nummonth=10;;
+ Nov) month=November; nummonth=11;;
+ Dec) month=December; nummonth=12;;
+esac
+
+case $3 in
+ ???*) day=$1;;
+ *) day=$3; shift;;
+esac
+
+# Here we have to deal with the problem that the ls output gives either
+# the time of day or the year.
+case $3 in
+ *:*) set `date`; eval year=\$$#
+ case $2 in
+ Jan) nummonthtod=1;;
+ Feb) nummonthtod=2;;
+ Mar) nummonthtod=3;;
+ Apr) nummonthtod=4;;
+ May) nummonthtod=5;;
+ Jun) nummonthtod=6;;
+ Jul) nummonthtod=7;;
+ Aug) nummonthtod=8;;
+ Sep) nummonthtod=9;;
+ Oct) nummonthtod=10;;
+ Nov) nummonthtod=11;;
+ Dec) nummonthtod=12;;
+ esac
+ # For the first six month of the year the time notation can also
+ # be used for files modified in the last year.
+ if (expr $nummonth \> $nummonthtod) > /dev/null;
+ then
+ year=`expr $year - 1`
+ fi;;
+ *) year=$3;;
+esac
+
+# The result.
+echo $day $month $year
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/qpid/cpp/build-aux/missing b/qpid/cpp/build-aux/missing
new file mode 100755
index 0000000000..1c8ff7049d
--- /dev/null
+++ b/qpid/cpp/build-aux/missing
@@ -0,0 +1,367 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+
+scriptversion=2006-05-10.23
+
+# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006
+# Free Software Foundation, Inc.
+# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+fi
+
+run=:
+sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p'
+sed_minuso='s/.* -o \([^ ]*\).*/\1/p'
+
+# In the cases where this matters, `missing' is being run in the
+# srcdir already.
+if test -f configure.ac; then
+ configure_ac=configure.ac
+else
+ configure_ac=configure.in
+fi
+
+msg="missing on your system"
+
+case $1 in
+--run)
+ # Try to run requested program, and just exit if it succeeds.
+ run=
+ shift
+ "$@" && exit 0
+ # Exit code 63 means version mismatch. This often happens
+ # when the user try to use an ancient version of a tool on
+ # a file that requires a minimum version. In this case we
+ # we should proceed has if the program had been absent, or
+ # if --run hadn't been passed.
+ if test $? = 63; then
+ run=:
+ msg="probably too old"
+ fi
+ ;;
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+ --run try to run the given command, and emulate it if it fails
+
+Supported PROGRAM values:
+ aclocal touch file \`aclocal.m4'
+ autoconf touch file \`configure'
+ autoheader touch file \`config.h.in'
+ autom4te touch the output file, or create a stub one
+ automake touch all \`Makefile.in' files
+ bison create \`y.tab.[ch]', if possible, from existing .[ch]
+ flex create \`lex.yy.c', if possible, from existing .c
+ help2man touch the output file
+ lex create \`lex.yy.c', if possible, from existing .c
+ makeinfo touch the output file
+ tar try tar, gnutar, gtar, then tar without non-portable flags
+ yacc create \`y.tab.[ch]', if possible, from existing .[ch]
+
+Send bug reports to <bug-automake@gnu.org>."
+ exit $?
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing $scriptversion (GNU Automake)"
+ exit $?
+ ;;
+
+ -*)
+ echo 1>&2 "$0: Unknown \`$1' option"
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+ ;;
+
+esac
+
+# Now exit if we have it, but it failed. Also exit now if we
+# don't have it and --version was passed (most likely to detect
+# the program).
+case $1 in
+ lex|yacc)
+ # Not GNU programs, they don't have --version.
+ ;;
+
+ tar)
+ if test -n "$run"; then
+ echo 1>&2 "ERROR: \`tar' requires --run"
+ exit 1
+ elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+ exit 1
+ fi
+ ;;
+
+ *)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+ # Could not run --version or --help. This is probably someone
+ # running `$TOOL --version' or `$TOOL --help' to check whether
+ # $TOOL exists and not knowing $TOOL uses missing.
+ exit 1
+ fi
+ ;;
+esac
+
+# If it does not exist, or fails to run (possibly an outdated version),
+# try to emulate it.
+case $1 in
+ aclocal*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`acinclude.m4' or \`${configure_ac}'. You might want
+ to install the \`Automake' and \`Perl' packages. Grab them from
+ any GNU archive site."
+ touch aclocal.m4
+ ;;
+
+ autoconf)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`${configure_ac}'. You might want to install the
+ \`Autoconf' and \`GNU m4' packages. Grab them from any GNU
+ archive site."
+ touch configure
+ ;;
+
+ autoheader)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`acconfig.h' or \`${configure_ac}'. You might want
+ to install the \`Autoconf' and \`GNU m4' packages. Grab them
+ from any GNU archive site."
+ files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
+ test -z "$files" && files="config.h"
+ touch_files=
+ for f in $files; do
+ case $f in
+ *:*) touch_files="$touch_files "`echo "$f" |
+ sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+ *) touch_files="$touch_files $f.in";;
+ esac
+ done
+ touch $touch_files
+ ;;
+
+ automake*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
+ You might want to install the \`Automake' and \`Perl' packages.
+ Grab them from any GNU archive site."
+ find . -type f -name Makefile.am -print |
+ sed 's/\.am$/.in/' |
+ while read f; do touch "$f"; done
+ ;;
+
+ autom4te)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, but is $msg.
+ You might have modified some files without having the
+ proper tools for further handling them.
+ You can get \`$1' as part of \`Autoconf' from any GNU
+ archive site."
+
+ file=`echo "$*" | sed -n "$sed_output"`
+ test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+ if test -f "$file"; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo "#! /bin/sh"
+ echo "# Created by GNU Automake missing as a replacement of"
+ echo "# $ $@"
+ echo "exit 0"
+ chmod +x $file
+ exit 1
+ fi
+ ;;
+
+ bison|yacc)
+ echo 1>&2 "\
+WARNING: \`$1' $msg. You should only need it if
+ you modified a \`.y' file. You may need the \`Bison' package
+ in order for those modifications to take effect. You can get
+ \`Bison' from any GNU archive site."
+ rm -f y.tab.c y.tab.h
+ if test $# -ne 1; then
+ eval LASTARG="\${$#}"
+ case $LASTARG in
+ *.y)
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+ if test -f "$SRCFILE"; then
+ cp "$SRCFILE" y.tab.c
+ fi
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+ if test -f "$SRCFILE"; then
+ cp "$SRCFILE" y.tab.h
+ fi
+ ;;
+ esac
+ fi
+ if test ! -f y.tab.h; then
+ echo >y.tab.h
+ fi
+ if test ! -f y.tab.c; then
+ echo 'main() { return 0; }' >y.tab.c
+ fi
+ ;;
+
+ lex|flex)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a \`.l' file. You may need the \`Flex' package
+ in order for those modifications to take effect. You can get
+ \`Flex' from any GNU archive site."
+ rm -f lex.yy.c
+ if test $# -ne 1; then
+ eval LASTARG="\${$#}"
+ case $LASTARG in
+ *.l)
+ SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+ if test -f "$SRCFILE"; then
+ cp "$SRCFILE" lex.yy.c
+ fi
+ ;;
+ esac
+ fi
+ if test ! -f lex.yy.c; then
+ echo 'main() { return 0; }' >lex.yy.c
+ fi
+ ;;
+
+ help2man)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a dependency of a manual page. You may need the
+ \`Help2man' package in order for those modifications to take
+ effect. You can get \`Help2man' from any GNU archive site."
+
+ file=`echo "$*" | sed -n "$sed_output"`
+ test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+ if test -f "$file"; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo ".ab help2man is required to generate this page"
+ exit 1
+ fi
+ ;;
+
+ makeinfo)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a \`.texi' or \`.texinfo' file, or any other file
+ indirectly affecting the aspect of the manual. The spurious
+ call might also be the consequence of using a buggy \`make' (AIX,
+ DU, IRIX). You might want to install the \`Texinfo' package or
+ the \`GNU make' package. Grab either from any GNU archive site."
+ # The file to touch is that specified with -o ...
+ file=`echo "$*" | sed -n "$sed_output"`
+ test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+ if test -z "$file"; then
+ # ... or it is the one specified with @setfilename ...
+ infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+ file=`sed -n '
+ /^@setfilename/{
+ s/.* \([^ ]*\) *$/\1/
+ p
+ q
+ }' $infile`
+ # ... or it is derived from the source name (dir/f.texi becomes f.info)
+ test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info
+ fi
+ # If the file does not exist, the user really needs makeinfo;
+ # let's fail without touching anything.
+ test -f $file || exit 1
+ touch $file
+ ;;
+
+ tar)
+ shift
+
+ # We have already tried tar in the generic part.
+ # Look for gnutar/gtar before invocation to avoid ugly error
+ # messages.
+ if (gnutar --version > /dev/null 2>&1); then
+ gnutar "$@" && exit 0
+ fi
+ if (gtar --version > /dev/null 2>&1); then
+ gtar "$@" && exit 0
+ fi
+ firstarg="$1"
+ if shift; then
+ case $firstarg in
+ *o*)
+ firstarg=`echo "$firstarg" | sed s/o//`
+ tar "$firstarg" "$@" && exit 0
+ ;;
+ esac
+ case $firstarg in
+ *h*)
+ firstarg=`echo "$firstarg" | sed s/h//`
+ tar "$firstarg" "$@" && exit 0
+ ;;
+ esac
+ fi
+
+ echo 1>&2 "\
+WARNING: I can't seem to be able to run \`tar' with the given arguments.
+ You may want to install GNU tar or Free paxutils, or check the
+ command line arguments."
+ exit 1
+ ;;
+
+ *)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, and is $msg.
+ You might have modified some files without having the
+ proper tools for further handling them. Check the \`README' file,
+ it often tells you about the needed prerequisites for installing
+ this package. You may also peek at any GNU archive site, in case
+ some other package would contain this missing \`$1' program."
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/qpid/cpp/configure.ac b/qpid/cpp/configure.ac
new file mode 100644
index 0000000000..c062fc3f8b
--- /dev/null
+++ b/qpid/cpp/configure.ac
@@ -0,0 +1,212 @@
+dnl Process this file with autoconf to produce a configure script.
+dnl
+dnl This file is free software; as a special exception the author gives
+dnl unlimited permission to copy and/or distribute it, with or without
+dnl modifications, as long as this notice is preserved.
+dnl
+dnl This program is distributed in the hope that it will be useful, but
+dnl WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+dnl implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+AC_INIT([qpidc], [0.2], [qpid-dev@incubator.apache.org])
+AC_CONFIG_AUX_DIR([build-aux])
+AM_INIT_AUTOMAKE([dist-bzip2 subdir-objects])
+
+# Minimum Autoconf version required.
+AC_PREREQ(2.59)
+
+AC_CONFIG_HEADERS([src/config.h])
+AC_CONFIG_SRCDIR([qpidc.spec.in])
+
+AC_PROG_CC_STDC
+AM_PROG_CC_C_O
+AC_PROG_CXX
+AC_USE_SYSTEM_EXTENSIONS
+AC_LANG([C++])
+
+# AM_MISSING_PROG([HELP2MAN], [help2man])
+AC_CHECK_PROG([HELP2MAN], [help2man], [help2man])
+test -z "$HELP2MAN" && AC_MSG_ERROR([Missing help2man installation (try "yum install help2man").])
+
+AC_ARG_ENABLE(warnings,
+[ --enable-warnings turn on lots of compiler warnings (recommended)],
+[case "${enableval}" in
+ yes|no) ;;
+ *) AC_MSG_ERROR([bad value ${enableval} for warnings option]) ;;
+ esac],
+ [enableval=yes])
+
+# Warnings: Enable as many as possible, keep the code clean. Please
+# do not disable warnings or remove -Werror without discussing on
+# qpid-dev list.
+#
+# The following warnings are deliberately omitted, they warn on valid code.
+# -Wunreachable-code -Wpadded -Winline
+# -Wshadow - warns about boost headers.
+
+if test "${enableval}" = yes; then
+ gl_COMPILER_FLAGS(-Werror)
+ gl_COMPILER_FLAGS(-pedantic)
+ gl_COMPILER_FLAGS(-Wall)
+ gl_COMPILER_FLAGS(-Wextra)
+ gl_COMPILER_FLAGS(-Wno-shadow)
+ gl_COMPILER_FLAGS(-Wpointer-arith)
+ gl_COMPILER_FLAGS(-Wcast-qual)
+ gl_COMPILER_FLAGS(-Wcast-align)
+ gl_COMPILER_FLAGS(-Wno-long-long)
+ gl_COMPILER_FLAGS(-Wvolatile-register-var)
+ gl_COMPILER_FLAGS(-Winvalid-pch)
+ gl_COMPILER_FLAGS(-Wno-system-headers)
+ gl_COMPILER_FLAGS(-Woverloaded-virtual)
+ AC_SUBST([WARNING_CFLAGS], [$COMPILER_FLAGS])
+ AC_DEFINE([lint], 1, [Define to 1 if the compiler is checking for lint.])
+ COMPILER_FLAGS=
+fi
+
+AC_DISABLE_STATIC
+AC_PROG_LIBTOOL
+AC_SUBST([LIBTOOL_DEPS])
+
+# For libraries (libcommon) that use dlopen, dlerror, etc.,
+# test whether we need to link with -ldl.
+gl_saved_libs=$LIBS
+ AC_SEARCH_LIBS(dlopen, [dl],
+ [test "$ac_cv_search_dlopen" = "none required" ||
+ LIB_DLOPEN=$ac_cv_search_dlopen])
+ AC_SUBST([LIB_DLOPEN])
+LIBS=$gl_saved_libs
+
+# Set the argument to be used in "libtool -version-info ARG".
+QPID_CURRENT=1
+QPID_REVISION=0
+QPID_AGE=1
+LIBTOOL_VERSION_INFO_ARG=$QPID_CURRENT:$QPID_REVISION:$QPID_AGE
+AC_SUBST(LIBTOOL_VERSION_INFO_ARG)
+
+gl_CLOCK_TIME
+
+# Check for cppunit support.
+CPPUNIT_MINIMUM_VERSION=1.10.2
+AM_PATH_CPPUNIT([$CPPUNIT_MINIMUM_VERSION], , [CPPUNIT_LIBS=-lcppunit])
+CPPUNIT_CXXFLAGS=$CPPUNIT_CFLAGS
+AC_SUBST(CPPUNIT_LIBS)
+AC_SUBST(CPPUNIT_CXXFLAGS)
+
+# Enable Valgrind
+AC_ARG_ENABLE([valgrind],
+ [AS_HELP_STRING([--enable-valgrind],
+ [run valgrind memory checker on tests, if available (default yes)])],
+ [case $enableval in
+ yes|no) enable_VALGRIND=$enableval;;
+ *) AC_MSG_ERROR([Invalid value for --enable-valgrind: $enableval]);;
+ esac],
+ [enable_VALGRIND=yes]
+)
+
+# We use valgrind for the tests. See if it's available.
+# Check for it unconditionally, so we don't have to duplicate its
+# use of AC_SUBST([VALGRIND]).
+AC_CHECK_PROG([VALGRIND], [valgrind], [valgrind])
+test "$enable_VALGRIND" = no && VALGRIND=
+
+# If rpmlint is availalbe we'll run it when building RPMs.
+AC_CHECK_PROG([RPMLINT], [rpmlint], [rpmlint])
+AM_CONDITIONAL([HAS_RPMLINT], [test -n "$RPMLINT"])
+
+# Code generation: generated code is included in the distribution
+# so code generation is only required in an svn checkout.
+# It requires several external tools and files, which we check for here.
+
+AC_CHECK_PROG([RUBY], [ruby], [ruby])
+test -n "$RUBY" && generate=yes
+test -z "$RUBY" && AC_MSG_ERROR([Missing ruby installation (try "yum install ruby").])
+
+specdir=`pwd`/$srcdir/../specs
+AMQP_PREVIEW_XML=$specdir/amqp.0-10-preview.xml
+AMQP_FINAL_XML=$specdir/amqp.0-10.xml
+AC_SUBST(AMQP_PREVIEW_XML)
+AC_SUBST(AMQP_FINAL_XML)
+AM_CONDITIONAL([GENERATE], [ls $AMQP_FINAL_XML >/dev/null])
+
+# URL and download URL for the package.
+URL=http://rhm.et.redhat.com/qpidc
+AC_SUBST(URL)
+DOWNLOAD_URL=http://rhm.et.redhat.com/download
+AC_SUBST(DOWNLOAD_URL)
+
+# Check for headers from required devel kits.
+AC_CHECK_HEADERS([boost/shared_ptr.hpp uuid/uuid.h],,
+ AC_MSG_ERROR([Missing required header files.]))
+
+# Check for optional CPG requirement.
+LDFLAGS="$LDFLAGS -L/usr/lib/openais -L/usr/lib64/openais"
+
+AC_ARG_WITH([cpg],
+ [AS_HELP_STRING([--with-cpg], [Build with CPG support])],
+ [case "${withval}" in
+ yes) # yes - enable
+ with_CPG=yes
+ AC_CHECK_LIB([cpg],[cpg_initialize],,[AC_MSG_ERROR([libcpg not found, install openais])])
+ AC_CHECK_HEADERS([openais/cpg.h],,[AC_MSG_ERROR([openais/cpg.h not found, install openais-devel])])
+ ;;
+ no) # no -disable
+ with_CPG=no
+ ;;
+ *) AC_MSG_ERROR([Bad value ${withval} for --with-cpg option]) ;;
+ esac],
+ [ # not specified - enable if libs/headers available.
+ with_CPG=yes
+ AC_CHECK_HEADERS([openais/cpg.h],,[with_CPG=no])
+ AC_CHECK_LIB([cpg],[cpg_initialize],,[with_CPG=no])
+ ]
+)
+AM_CONDITIONAL([CPG], [test x$with_CPG = xyes])
+if test x$with_CPG = xyes; then
+ CPPFLAGS+=" -DCPG"
+fi
+
+
+# Setup --with-sasl/--without-sasl as arguments to configure
+AC_ARG_WITH([sasl],
+ [AS_HELP_STRING([--with-sasl], [Build with SASL authentication support])],
+ [WANT_SASL="$withval"],
+ [WANT_SASL=check])
+
+# Make sure --with-sasl/--without-sasl were only give yes|no|check
+AS_IF([test "x$WANT_SASL" != xyes -a \
+ "x$WANT_SASL" != xno -a \
+ "x$WANT_SASL" != xcheck],
+ [AC_MSG_ERROR([Bad value for --with-sasl: $withval])])
+
+# If we weren't explicitly asked /not/ to test, i.e. not given --without-sasl
+AS_IF([test "x$WANT_SASL" != xno],
+ # Perform tests for headers and libraries. Remember, AC_CHECK_LIB
+ # will give you some useful default behavior, e.g. setup LDFLAGS, if
+ # you do not give it a second argument, so try not to
+ [AC_CHECK_HEADER([sasl/sasl.h], , [HAVE_SASL_H=no])
+ AC_CHECK_LIB([sasl2], [sasl_checkpass], , [HAVE_SASL_LIB=no])
+ # If any of the tests failed
+ AS_IF([test "x$HAVE_SASL_H" = xno -o \
+ "x$HAVE_SASL_LIB" = xno],
+ # And we were given --with, then fail
+ [AS_IF([test "x$WANT_SASL" = xyes],
+ [AC_MSG_ERROR([sasl requested but not available])])],
+ # Otherwise, no tests failed, setup AC_SUBST/AC_DEFINE/AM_CONDITIONALs
+ [AC_DEFINE([BROKER_SASL_NAME], ["qpidd"],
+ [The SASL app name for the qpid Broker])
+ AC_DEFINE([HAVE_SASL], [1], [Enable if libsasl is present])])])
+
+# Files to generate
+AC_CONFIG_FILES([
+ qpidc.spec
+ Makefile
+ examples/Makefile
+ src/Makefile
+ src/tests/Makefile
+ docs/man/Makefile
+ docs/api/Makefile
+ docs/api/user.doxygen
+ docs/api/developer.doxygen
+ ])
+AC_OUTPUT
+
diff --git a/qpid/cpp/docs/api/Makefile.am b/qpid/cpp/docs/api/Makefile.am
new file mode 100644
index 0000000000..bde8b5fa3d
--- /dev/null
+++ b/qpid/cpp/docs/api/Makefile.am
@@ -0,0 +1,18 @@
+#
+# Run doxygen to generate HTML doc.
+# Generate dependency files so its rebuilt only when needed.
+#
+
+# TODO aconway 2007-04-12: html should have a
+# dependency on source/header files.
+
+EXTRA_DIST = html user.doxygen developer.doxygen html.timestamp
+
+html: html.timestamp
+
+html.timestamp:
+ doxygen user.doxygen
+ touch $@
+
+clean-local:
+ rm -rf html html-dev html.timestamp
diff --git a/qpid/cpp/docs/api/developer.doxygen.in b/qpid/cpp/docs/api/developer.doxygen.in
new file mode 100644
index 0000000000..b267b12b90
--- /dev/null
+++ b/qpid/cpp/docs/api/developer.doxygen.in
@@ -0,0 +1,1241 @@
+ # ----------------------------------------------------------------
+# Doxygen settings for Qpid developer documentation.
+#
+# ----------------------------------------------------------------
+
+# Doxyfile 1.4.6
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = Qpid
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = 0
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = .
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish,
+# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese,
+# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish,
+# Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# This tag can be used to specify the encoding used in the generated output.
+# The encoding is not always determined by the language that is chosen,
+# but also whether or not the output is meant for Windows or non-Windows users.
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES
+# forces the Windows encoding (this is the default for the Windows binary),
+# whereas setting the tag to NO uses a Unix-style encoding (the default for
+# all platforms other than Windows).
+
+USE_WINDOWS_ENCODING = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = YES
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to
+# include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = YES
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from the
+# version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE = doxygen.log
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = @abs_top_srcdir@/src
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+
+
+FILE_PATTERNS = *.h *.cpp
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE = test
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html-dev
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = NO
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = YES
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = YES
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a call dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_WIDTH = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT = 1024
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that a graph may be further truncated if the graph's
+# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH
+# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default),
+# the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, which results in a white background.
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = YES
diff --git a/qpid/cpp/docs/api/user.doxygen.in b/qpid/cpp/docs/api/user.doxygen.in
new file mode 100644
index 0000000000..4b65b73347
--- /dev/null
+++ b/qpid/cpp/docs/api/user.doxygen.in
@@ -0,0 +1,1218 @@
+# ----------------------------------------------------------------
+# Doxygen settings for Qpid user documentation.
+#
+# Note: Only public members of classes that are part of the public API
+# should be documented here. For complete developer documentation use
+# the developer.doxygen configuration.
+# ----------------------------------------------------------------
+
+# Doxyfile 1.4.6
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = Qpid
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = 0
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = .
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish,
+# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese,
+# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish,
+# Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = YES
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to
+# include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = NO
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = YES
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = YES
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = YES
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from the
+# version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE = doxygen.log
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = @abs_top_srcdir@/src @abs_top_builddir@/src/gen
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+
+
+FILE_PATTERNS = *.h
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE = test
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = YES
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = YES
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a call dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that a graph may be further truncated if the graph's
+# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH
+# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default),
+# the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, which results in a white background.
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = YES
diff --git a/qpid/cpp/docs/man/Makefile.am b/qpid/cpp/docs/man/Makefile.am
new file mode 100644
index 0000000000..c8df4eab6a
--- /dev/null
+++ b/qpid/cpp/docs/man/Makefile.am
@@ -0,0 +1,20 @@
+dist_man_MANS = qpidd.1
+
+man_aux = $(dist_man_MANS:.1=.x)
+EXTRA_DIST = $(man_aux)
+DISTCLEANFILES = $(dist_man_MANS)
+
+dist-hook: $(man_aux)
+
+qpidd.1: $(srcdir)/qpidd.x $(top_builddir)/src/qpidd
+
+# Depend on configure.ac to get version number changes.
+$(dist_man_MANS): $(top_srcdir)/configure.ac
+
+SUFFIXES = .x .1
+.x.1:
+ @rm -f $@
+ @echo "Updating man page $@"
+ $(HELP2MAN) --no-info --include=$(srcdir)/$*.x --output=$@-t ../../src/$*
+ @chmod a-w $@-t
+ @mv $@-t $@
diff --git a/qpid/cpp/docs/man/qpidd.x b/qpid/cpp/docs/man/qpidd.x
new file mode 100644
index 0000000000..edbe7b3bff
--- /dev/null
+++ b/qpid/cpp/docs/man/qpidd.x
@@ -0,0 +1,46 @@
+[NAME]
+
+qpidd \- the Qpid AMQP Broker Daemon
+
+[SYNOPSIS]
+
+qpidd [options]
+
+[DESCRIPTION]
+
+An AMQP broker daemon that stores, routes and forwards messages using
+the Advanced Message Queueing Protocol (AMQP).
+
+[OPTIONS]
+
+Options may be specified via command line, environment variable or configuration file. See FILES and ENVIRONMENT below for details.
+
+[FILES]
+.I /etc/qpidd.conf
+.RS
+Default configuration file.
+.RE
+
+Configuration file settings are over-ridden by command line or environment variable settings. '--config <file>' or 'export QPID_CONFIG=<file>' specifies an alternate file.
+
+Each line is a name=value pair. Blank lines and lines beginning with # are ignored. For example:
+
+ # My qpidd configuration file.
+ port=6000
+ max-connections=10
+ log-output=stdout
+ log-output=/tmp/qpidd.log
+
+[ENVIRONMENT]
+.I QPID_<option>
+.RS
+There is an environment variable for each option.
+.RE
+
+The environment variable is the option name in uppercase, prefixed with QPID_ and '.' or '-' are replaced with '_'. Environment settings are over-ridden by command line settings. For example:
+
+ export QPID_PORT=6000
+ export QPID_MAX_CONNECTIONS=10
+ export QPID_LOG_OUTPUT=/tmp/qpidd.log
+
+
diff --git a/qpid/cpp/etc/qpidd b/qpid/cpp/etc/qpidd
new file mode 100755
index 0000000000..d9076191d6
--- /dev/null
+++ b/qpid/cpp/etc/qpidd
@@ -0,0 +1,85 @@
+#!/bin/bash
+#
+# qpidd Startup script for the Qpid messaging daemon.
+#
+
+### BEGIN INIT INFO
+# Provides: qpidd
+# Required-Start: $local_fs
+# Required-Stop: $local_fs
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: start or stop qpidd
+# Description: Qpidd is an AMQP broker. It receives, stores, routes and forwards messages using the AMQP protcol.
+### END INIT INFO
+
+# chkconfig: - 85 15
+# description: Qpidd is an AMQP broker. It receives, stores, routes and forwards messages using the AMQP protcol.
+# processname: qpidd
+
+prog=qpidd
+lockfile=/var/lock/subsys/$prog
+pidfile=/var/run/qpidd.pid
+
+# Source function library.
+. /etc/rc.d/init.d/functions
+
+if [ -f /etc/sysconfig/$prog ] ; then
+ . /etc/sysconfig/$prog
+fi
+
+RETVAL=0
+
+start() {
+ echo -n $"Starting Qpid AMQP daemon: "
+ daemon --pidfile $pidfile --check $prog --user qpidd $prog --daemon $QPIDD_OPTIONS
+ RETVAL=$?
+ echo
+ [ $RETVAL = 0 ] && touch $lockfile
+ if [ $RETVAL = 0 ]; then
+ touch $pidfile
+ chown qpidd.qpidd $pidfile
+ runuser -s /bin/sh qpidd -c "qpidd -c > $pidfile"
+ fi
+ return $RETVAL
+}
+
+stop() {
+ echo -n $"Stopping Qpid AMQP daemon: "
+ killproc -p ${pidfile} $prog
+ RETVAL=$?
+ echo
+ [ $RETVAL = 0 ] && rm -f ${lockfile} ${pidfile}
+}
+
+reload() {
+ echo 1>&2 $"$0: reload not supported"
+ exit 3
+}
+
+restart() {
+ stop
+ start
+}
+
+# See how we were called.
+case "$1" in
+ start|stop|restart|reload)
+ $1
+ ;;
+ status)
+ status $prog
+ RETVAL=$?
+ ;;
+ force-reload)
+ restart
+ ;;
+ try-restart)
+ [ -e $lockfile ] && restart || :
+ ;;
+ *)
+ echo 1>&2 $"Usage: $0 {start|stop|restart|condrestart|status}"
+ exit 1
+esac
+
+exit $RETVAL
diff --git a/qpid/cpp/etc/qpidd.conf b/qpid/cpp/etc/qpidd.conf
new file mode 100644
index 0000000000..8064767e78
--- /dev/null
+++ b/qpid/cpp/etc/qpidd.conf
@@ -0,0 +1,2 @@
+# Configuration file for qpidd.
+# Using default settings, qpidd --help to see defaults.
diff --git a/qpid/cpp/examples/Makefile.am b/qpid/cpp/examples/Makefile.am
new file mode 100644
index 0000000000..540e092ea2
--- /dev/null
+++ b/qpid/cpp/examples/Makefile.am
@@ -0,0 +1,79 @@
+
+# List all example files here
+nobase_pkgdata_DATA= \
+ examples/Makefile \
+ examples/request-response/client.cpp \
+ examples/request-response/server.cpp \
+ examples/request-response/Makefile \
+ examples/fanout/Makefile \
+ examples/fanout/listener.cpp \
+ examples/fanout/fanout_producer.cpp \
+ examples/pub-sub/Makefile \
+ examples/pub-sub/topic_publisher.cpp \
+ examples/pub-sub/topic_listener.cpp \
+ examples/direct/Makefile \
+ examples/direct/direct_producer.cpp \
+ examples/direct/listener.cpp \
+ examples/direct/declare_queues.cpp
+
+VERIFY_FILES= verify verify_all \
+ examples/request-response/verify \
+ examples/request-response/verify.in \
+ examples/request-response/verify_cpp_python \
+ examples/request-response/verify_cpp_python.in \
+ examples/request-response/verify_python_cpp \
+ examples/request-response/verify_python_cpp.in \
+ examples/fanout/verify \
+ examples/fanout/verify.in \
+ examples/fanout/verify_cpp_python \
+ examples/fanout/verify_cpp_python.in \
+ examples/fanout/verify_python_cpp \
+ examples/fanout/verify_python_cpp.in \
+ examples/pub-sub/verify \
+ examples/pub-sub/verify.in \
+ examples/pub-sub/verify_cpp_python \
+ examples/pub-sub/verify_cpp_python.in \
+ examples/pub-sub/verify_python_cpp \
+ examples/pub-sub/verify_python_cpp.in \
+ examples/direct/verify \
+ examples/direct/verify.in \
+ examples/direct/verify_cpp_python \
+ examples/direct/verify_cpp_python.in \
+ examples/direct/verify_python_cpp \
+ examples/direct/verify_python_cpp.in
+
+EXTRA_DIST=$(nobase_pkgdata_DATA) $(VERIFY_FILES)
+
+# Note: we don't use normal automake SUBDIRS because the example
+# makefiles don't understand all the recursive automake targets.
+
+clean-local:
+ cd examples; $(MAKE) clean
+ rm -f examples/*/*.out examples/*/*.wait
+
+abs_top_builddir=@abs_top_builddir@
+abs_top_srcdir=@abs_top_srcdir@
+
+# Build the examples - copy sources to the build tree in VPATH build.
+all-local:
+ test -d examples || cp -R $(srcdir)/examples .
+ cd examples && $(MAKE) CXX="$(CXX)" CXXFLAGS="$(CXXFLAGS) -I../../$(top_srcdir)/src -I../../$(top_srcdir)/src/gen -I../../$(top_builddir)/src/gen -L../../$(top_builddir)/src/.libs -Wl,-rpath,$(abs_top_builddir)/src/.libs" all
+
+# FIXME aconway 2008-03-25: Re-enable when python client has been fixed
+# to find .spec via PYTHONPATH.
+#
+# Verify the examples in the buid tree.
+# check-local: all-local verify
+# $(srcdir)/verify_all $(abs_top_srcdir)/..
+
+# TODO:
+# create a tarball for testing installed examples.
+# installcheck-local to use the tarball on installed example and clean up after.
+# Build and verify installed C++ examples, clean up to avoid rpmbuild warnings.
+# EXAMPLE_FLAGS=-I$(DESTDIR)$(includedir) -L$(DESTDIR)$(libdir) -Wl,-rpath,$(DESTDIR)$(libdir)
+# EXAMPLE_DIR=$(DESTDIR)$(pkgdatadir)/examples/cpp
+# installcheck-local:
+# cd $(EXAMPLE_DIR) && $(MAKE) CXX="$(CXX)" CXXFLAGS="$(EXAMPLE_FLAGS)" all
+# cd $(EXAMPLE_DIR) && QPIDD=$(sbindir)/qpidd $(srcdir)/verify *
+# cd $(EXAMPLE_DIR) && $(MAKE) clean
+
diff --git a/qpid/cpp/examples/examples/Makefile b/qpid/cpp/examples/examples/Makefile
new file mode 100644
index 0000000000..8591bd3361
--- /dev/null
+++ b/qpid/cpp/examples/examples/Makefile
@@ -0,0 +1,6 @@
+SUBDIRS=direct fanout pub-sub request-response
+all:
+ for d in $(SUBDIRS); do ( cd $$d; $(MAKE) $@; ) ; done
+clean:
+ for d in $(SUBDIRS); do ( cd $$d; $(MAKE) $@; ) ; done
+
diff --git a/qpid/cpp/examples/examples/direct/Makefile b/qpid/cpp/examples/examples/direct/Makefile
new file mode 100644
index 0000000000..380b5cfcb4
--- /dev/null
+++ b/qpid/cpp/examples/examples/direct/Makefile
@@ -0,0 +1,10 @@
+CXX=g++
+CXXFLAGS=
+LDFLAGS=-lqpidclient
+
+PROGRAMS=declare_queues direct_producer listener
+
+all: $(PROGRAMS)
+
+clean:
+ rm -f $(PROGRAMS)
diff --git a/qpid/cpp/examples/examples/direct/declare_queues.cpp b/qpid/cpp/examples/examples/direct/declare_queues.cpp
new file mode 100644
index 0000000000..de7eff0490
--- /dev/null
+++ b/qpid/cpp/examples/examples/direct/declare_queues.cpp
@@ -0,0 +1,86 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/**
+ * declare_queues.cpp
+ *
+ * This program is one of three programs designed to be used
+ * together. These programs use the "amq.direct" exchange.
+ *
+ * direct_config_queues.cpp (this program):
+ *
+ * Creates a queue on a broker, binding a routing key to route
+ * messages to that queue.
+ *
+ * direct_producer.cpp:
+ *
+ * Publishes to a broker, specifying a routing key.
+ *
+ * listener.cpp
+ *
+ * Reads from a queue on the broker using a message listener.
+ *
+ */
+
+#include <qpid/client/Connection.h>
+#include <qpid/client/Session.h>
+
+#include <unistd.h>
+#include <cstdlib>
+#include <iostream>
+
+using namespace qpid::client;
+using namespace qpid::framing;
+
+using std::string;
+
+
+int main(int argc, char** argv) {
+ const char* host = argc>1 ? argv[1] : "127.0.0.1";
+ int port = argc>2 ? atoi(argv[2]) : 5672;
+ Connection connection;
+ Message msg;
+ try {
+ connection.open(host, port);
+ Session session = connection.newSession(ASYNC);
+
+
+ //--------- Main body of program --------------------------------------------
+
+ // Create a queue named "message_queue", and route all messages whose
+ // routing key is "routing_key to this newly created queue.
+
+ session.queueDeclare(arg::queue="message_queue");
+ session.queueBind(arg::exchange="amq.direct", arg::queue="message_queue", arg::routingKey="routing_key");
+
+ //-----------------------------------------------------------------------------
+
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+
+}
+
+
+
diff --git a/qpid/cpp/examples/examples/direct/direct_producer.cpp b/qpid/cpp/examples/examples/direct/direct_producer.cpp
new file mode 100644
index 0000000000..9b40f733c2
--- /dev/null
+++ b/qpid/cpp/examples/examples/direct/direct_producer.cpp
@@ -0,0 +1,106 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+
+/**
+ * direct_producer.cpp:
+ *
+ * This program is one of three programs designed to be used
+ * together. These programs do not specify the exchange type - the
+ * default exchange type is the direct exchange.
+ *
+ * create_queues.cpp:
+ *
+ * Creates a queue on a broker, binding a routing key to route
+ * messages to that queue.
+ *
+ * direct_producer.cpp (this program):
+ *
+ * Publishes to a broker, specifying a routing key.
+ *
+ * listener.cpp
+ *
+ * Reads from a queue on the broker using a message listener.
+ *
+ */
+
+
+#include <qpid/client/Connection.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/Message.h>
+
+
+#include <unistd.h>
+#include <cstdlib>
+#include <iostream>
+
+#include <sstream>
+
+using namespace qpid::client;
+using namespace qpid::framing;
+
+using std::stringstream;
+using std::string;
+
+int main(int argc, char** argv) {
+ const char* host = argc>1 ? argv[1] : "127.0.0.1";
+ int port = argc>2 ? atoi(argv[2]) : 5672;
+ Connection connection;
+ Message message;
+ try {
+ connection.open(host, port);
+ Session session = connection.newSession(ASYNC);
+
+ //--------- Main body of program --------------------------------------------
+
+ // The routing key is a message property. We will use the same
+ // routing key for each message, so we'll set this property
+ // just once. (In most simple cases, there is no need to set
+ // other message properties.)
+
+ message.getDeliveryProperties().setRoutingKey("routing_key");
+
+ // Now send some messages ...
+
+ for (int i=0; i<10; i++) {
+ stringstream message_data;
+ message_data << "Message " << i;
+
+ message.setData(message_data.str());
+ session.messageTransfer(arg::content=message, arg::destination="amq.direct");
+ }
+
+ // And send a final message to indicate termination.
+
+ message.setData("That's all, folks!");
+ session.messageTransfer(arg::content=message, arg::destination="amq.direct");
+
+ //-----------------------------------------------------------------------------
+
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/qpid/cpp/examples/examples/direct/listener.cpp b/qpid/cpp/examples/examples/direct/listener.cpp
new file mode 100644
index 0000000000..ae6a7699f1
--- /dev/null
+++ b/qpid/cpp/examples/examples/direct/listener.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.
+ *
+ */
+
+/**
+ * listener.cpp: This program reads messages fro a queue on
+ * the broker using a message listener.
+ */
+
+#include <qpid/client/Dispatcher.h>
+#include <qpid/client/Connection.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/Message.h>
+#include <qpid/client/SubscriptionManager.h>
+
+#include <unistd.h>
+#include <cstdlib>
+#include <iostream>
+
+using namespace qpid::client;
+using namespace qpid::framing;
+
+
+class Listener : public MessageListener{
+ private:
+ SubscriptionManager& subscriptions;
+ public:
+ Listener(SubscriptionManager& subscriptions);
+ virtual void received(Message& message);
+};
+
+Listener::Listener(SubscriptionManager& subs) : subscriptions(subs)
+{}
+
+void Listener::received(Message& message) {
+ std::cout << "Message: " << message.getData() << std::endl;
+ if (message.getData() == "That's all, folks!") {
+ std::cout << "Shutting down listener for " << message.getDestination()
+ << std::endl;
+ subscriptions.cancel(message.getDestination());
+ }
+}
+
+int main(int argc, char** argv) {
+ const char* host = argc>1 ? argv[1] : "127.0.0.1";
+ int port = argc>2 ? atoi(argv[2]) : 5672;
+ Connection connection;
+ Message msg;
+ try {
+ connection.open(host, port);
+ Session session = connection.newSession(ASYNC);
+
+ //--------- Main body of program --------------------------------------------
+
+ SubscriptionManager subscriptions(session);
+ // Create a listener and subscribe it to the queue named "message_queue"
+ Listener listener(subscriptions);
+ subscriptions.subscribe(listener, "message_queue");
+ // Deliver messages until the subscription is cancelled
+ // by Listener::received()
+ subscriptions.run();
+
+ //---------------------------------------------------------------------------
+
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/qpid/cpp/examples/examples/direct/verify b/qpid/cpp/examples/examples/direct/verify
new file mode 100644
index 0000000000..ac0464ef80
--- /dev/null
+++ b/qpid/cpp/examples/examples/direct/verify
@@ -0,0 +1,3 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+clients ./declare_queues ./direct_producer ./listener
+outputs ./declare_queues.out ./direct_producer.out ./listener.out
diff --git a/qpid/cpp/examples/examples/direct/verify.in b/qpid/cpp/examples/examples/direct/verify.in
new file mode 100644
index 0000000000..d1e95f1151
--- /dev/null
+++ b/qpid/cpp/examples/examples/direct/verify.in
@@ -0,0 +1,15 @@
+==== declare_queues.out
+==== direct_producer.out
+==== listener.out
+Message: Message 0
+Message: Message 1
+Message: Message 2
+Message: Message 3
+Message: Message 4
+Message: Message 5
+Message: Message 6
+Message: Message 7
+Message: Message 8
+Message: Message 9
+Message: That's all, folks!
+Shutting down listener for message_queue
diff --git a/qpid/cpp/examples/examples/direct/verify_cpp_python b/qpid/cpp/examples/examples/direct/verify_cpp_python
new file mode 100644
index 0000000000..4dc445ba27
--- /dev/null
+++ b/qpid/cpp/examples/examples/direct/verify_cpp_python
@@ -0,0 +1,4 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+py=$PYTHON_EXAMPLES/direct
+clients ./declare_queues ./direct_producer $py/direct_consumer.py
+outputs ./declare_queues.out ./direct_producer.out $py/direct_consumer.py.out
diff --git a/qpid/cpp/examples/examples/direct/verify_cpp_python.in b/qpid/cpp/examples/examples/direct/verify_cpp_python.in
new file mode 100644
index 0000000000..1a329be59a
--- /dev/null
+++ b/qpid/cpp/examples/examples/direct/verify_cpp_python.in
@@ -0,0 +1,14 @@
+==== declare_queues.out
+==== direct_producer.out
+==== direct_consumer.py.out
+Message 0
+Message 1
+Message 2
+Message 3
+Message 4
+Message 5
+Message 6
+Message 7
+Message 8
+Message 9
+That's all, folks!
diff --git a/qpid/cpp/examples/examples/direct/verify_python_cpp b/qpid/cpp/examples/examples/direct/verify_python_cpp
new file mode 100644
index 0000000000..fe4893e120
--- /dev/null
+++ b/qpid/cpp/examples/examples/direct/verify_python_cpp
@@ -0,0 +1,5 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+py=$PYTHON_EXAMPLES/direct
+clients $py/declare_queues.py $py/direct_producer.py ./listener
+outputs $py/declare_queues.py.out $py/direct_producer.py.out ./listener.out
+
diff --git a/qpid/cpp/examples/examples/direct/verify_python_cpp.in b/qpid/cpp/examples/examples/direct/verify_python_cpp.in
new file mode 100644
index 0000000000..6f35255b18
--- /dev/null
+++ b/qpid/cpp/examples/examples/direct/verify_python_cpp.in
@@ -0,0 +1,15 @@
+==== declare_queues.py.out
+==== direct_producer.py.out
+==== listener.out
+Message: message 0
+Message: message 1
+Message: message 2
+Message: message 3
+Message: message 4
+Message: message 5
+Message: message 6
+Message: message 7
+Message: message 8
+Message: message 9
+Message: That's all, folks!
+Shutting down listener for message_queue
diff --git a/qpid/cpp/examples/examples/fanout/Makefile b/qpid/cpp/examples/examples/fanout/Makefile
new file mode 100644
index 0000000000..7963af7ddf
--- /dev/null
+++ b/qpid/cpp/examples/examples/fanout/Makefile
@@ -0,0 +1,10 @@
+CXX=g++
+CXXFLAGS=
+LDFLAGS=-lqpidclient
+
+PROGRAMS=fanout_producer listener
+
+all: $(PROGRAMS)
+
+clean:
+ rm -f $(PROGRAMS)
diff --git a/qpid/cpp/examples/examples/fanout/fanout_producer.cpp b/qpid/cpp/examples/examples/fanout/fanout_producer.cpp
new file mode 100644
index 0000000000..8ae6bbc242
--- /dev/null
+++ b/qpid/cpp/examples/examples/fanout/fanout_producer.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.
+ *
+ */
+
+
+/**
+ * fanout_producer.cpp:
+ *
+ * This program is one of three programs designed to be used
+ * together. These programs do not specify the exchange type - the
+ * default exchange type is the direct exchange.
+ *
+ * declare_queues.cpp:
+ *
+ * Creates a queue on a broker, binding a routing key to route
+ * messages to that queue.
+ *
+ * fanout_producer.cpp (this program):
+ *
+ * Publishes to a broker, specifying a routing key.
+ *
+ * listener.cpp
+ *
+ * Reads from a queue on the broker using a message listener.
+ *
+ */
+
+
+#include <qpid/client/Connection.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/Message.h>
+
+
+#include <unistd.h>
+#include <cstdlib>
+#include <iostream>
+
+#include <sstream>
+
+using namespace qpid::client;
+using namespace qpid::framing;
+
+using std::stringstream;
+using std::string;
+
+int main(int argc, char** argv) {
+ const char* host = argc>1 ? argv[1] : "127.0.0.1";
+ int port = argc>2 ? atoi(argv[2]) : 5672;
+ Connection connection;
+ Message message;
+ try {
+ connection.open(host, port);
+ Session session = connection.newSession(ASYNC);
+
+ //--------- Main body of program --------------------------------------------
+
+ // Unlike topic exchanges and direct exchanges, a fanout
+ // exchange need not set a routing key.
+
+ Message message;
+
+ // Now send some messages ...
+
+ for (int i=0; i<10; i++) {
+ stringstream message_data;
+ message_data << "Message " << i;
+
+ message.setData(message_data.str());
+ session.messageTransfer(arg::content=message, arg::destination="amq.fanout");
+ }
+
+ // And send a final message to indicate termination.
+
+ message.setData("That's all, folks!");
+ session.messageTransfer(arg::content=message, arg::destination="amq.fanout");
+
+ //-----------------------------------------------------------------------------
+
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/qpid/cpp/examples/examples/fanout/listener.cpp b/qpid/cpp/examples/examples/fanout/listener.cpp
new file mode 100644
index 0000000000..2860528b1f
--- /dev/null
+++ b/qpid/cpp/examples/examples/fanout/listener.cpp
@@ -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.
+ *
+ */
+
+/**
+ * listener.cpp: This program reads messages fro a queue on
+ * the broker using a message listener.
+ */
+
+#include <qpid/client/Dispatcher.h>
+#include <qpid/client/Connection.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/Message.h>
+#include <qpid/client/SubscriptionManager.h>
+
+#include <unistd.h>
+#include <cstdlib>
+#include <iostream>
+
+using namespace qpid::client;
+using namespace qpid::framing;
+
+
+class Listener : public MessageListener{
+ private:
+ SubscriptionManager& subscriptions;
+ public:
+ Listener(SubscriptionManager& subscriptions);
+ virtual void received(Message& message);
+};
+
+Listener::Listener(SubscriptionManager& subs) : subscriptions(subs)
+{}
+
+void Listener::received(Message& message) {
+ std::cout << "Message: " << message.getData() << std::endl;
+ if (message.getData() == "That's all, folks!") {
+ std::cout << "Shutting down listener for " << message.getDestination()
+ << std::endl;
+ subscriptions.cancel(message.getDestination());
+ }
+}
+
+int main(int argc, char** argv) {
+ const char* host = argc>1 ? argv[1] : "127.0.0.1";
+ int port = argc>2 ? atoi(argv[2]) : 5672;
+ Connection connection;
+ Message msg;
+ try {
+ connection.open(host, port);
+ Session session = connection.newSession(ASYNC);
+
+ //--------- Main body of program --------------------------------------------
+
+ // Unique name for private queue:
+ std::string myQueue=session.getId().str();
+ // Declear my queue.
+ session.queueDeclare(arg::queue=myQueue, arg::exclusive=true,
+ arg::autoDelete=true);
+ // Bind my queue to the fanout exchange.
+ // Note no routingKey required, the fanout exchange delivers
+ // all messages to all bound queues unconditionally.
+ session.queueBind(arg::exchange="amq.fanout", arg::queue=myQueue);
+
+ // Create a listener and subscribe it to my queue.
+ SubscriptionManager subscriptions(session);
+ Listener listener(subscriptions);
+ subscriptions.subscribe(listener, myQueue);
+
+ // Wait for the broker to indicate that our queues have been created.
+ session.sync();
+
+ // Deliver messages until the subscription is cancelled
+ // by Listener::received()
+ std::cout << "Listening" << std::endl;
+ subscriptions.run();
+
+ //---------------------------------------------------------------------------
+
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/qpid/cpp/examples/examples/fanout/verify b/qpid/cpp/examples/examples/fanout/verify
new file mode 100644
index 0000000000..ace4a6dfee
--- /dev/null
+++ b/qpid/cpp/examples/examples/fanout/verify
@@ -0,0 +1,6 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+background "Listening" ./listener
+background "Listening" ./listener
+background "Listening" ./listener
+clients ./fanout_producer
+outputs ./fanout_producer.out "./listener.out | remove_uuid" "./listenerX.out | remove_uuid" "./listenerXX.out | remove_uuid"
diff --git a/qpid/cpp/examples/examples/fanout/verify.in b/qpid/cpp/examples/examples/fanout/verify.in
new file mode 100644
index 0000000000..8f8612ce67
--- /dev/null
+++ b/qpid/cpp/examples/examples/fanout/verify.in
@@ -0,0 +1,43 @@
+==== fanout_producer.out
+==== listener.out | remove_uuid
+Listening
+Message: Message 0
+Message: Message 1
+Message: Message 2
+Message: Message 3
+Message: Message 4
+Message: Message 5
+Message: Message 6
+Message: Message 7
+Message: Message 8
+Message: Message 9
+Message: That's all, folks!
+Shutting down listener for
+==== listenerX.out | remove_uuid
+Listening
+Message: Message 0
+Message: Message 1
+Message: Message 2
+Message: Message 3
+Message: Message 4
+Message: Message 5
+Message: Message 6
+Message: Message 7
+Message: Message 8
+Message: Message 9
+Message: That's all, folks!
+Shutting down listener for
+==== listenerXX.out | remove_uuid
+Listening
+Message: Message 0
+Message: Message 1
+Message: Message 2
+Message: Message 3
+Message: Message 4
+Message: Message 5
+Message: Message 6
+Message: Message 7
+Message: Message 8
+Message: Message 9
+Message: That's all, folks!
+Shutting down listener for
diff --git a/qpid/cpp/examples/examples/fanout/verify_cpp_python b/qpid/cpp/examples/examples/fanout/verify_cpp_python
new file mode 100644
index 0000000000..e840e68f91
--- /dev/null
+++ b/qpid/cpp/examples/examples/fanout/verify_cpp_python
@@ -0,0 +1,7 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+py=$PYTHON_EXAMPLES/fanout
+background "Subscribed" $py/fanout_consumer.py
+background "Subscribed" $py/fanout_consumer.py
+clients ./fanout_producer
+outputs ./fanout_producer.out "$py/fanout_consumer.py.out | remove_uuid64" "$py/fanout_consumer.pyX.out | remove_uuid64"
+
diff --git a/qpid/cpp/examples/examples/fanout/verify_cpp_python.in b/qpid/cpp/examples/examples/fanout/verify_cpp_python.in
new file mode 100644
index 0000000000..fac2b365d3
--- /dev/null
+++ b/qpid/cpp/examples/examples/fanout/verify_cpp_python.in
@@ -0,0 +1,31 @@
+==== fanout_producer.out
+==== fanout_consumer.py.out | remove_uuid64
+Messages queue:
+Subscribed to queue
+Response: Message 0
+Response: Message 1
+Response: Message 2
+Response: Message 3
+Response: Message 4
+Response: Message 5
+Response: Message 6
+Response: Message 7
+Response: Message 8
+Response: Message 9
+Response: That's all, folks!
+No more messages!
+==== fanout_consumer.pyX.out | remove_uuid64
+Messages queue:
+Subscribed to queue
+Response: Message 0
+Response: Message 1
+Response: Message 2
+Response: Message 3
+Response: Message 4
+Response: Message 5
+Response: Message 6
+Response: Message 7
+Response: Message 8
+Response: Message 9
+Response: That's all, folks!
+No more messages!
diff --git a/qpid/cpp/examples/examples/fanout/verify_python_cpp b/qpid/cpp/examples/examples/fanout/verify_python_cpp
new file mode 100644
index 0000000000..d9b3361523
--- /dev/null
+++ b/qpid/cpp/examples/examples/fanout/verify_python_cpp
@@ -0,0 +1,7 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+py=$PYTHON_EXAMPLES/fanout
+background "Listening" ./listener
+background "Listening" ./listener
+clients $py/fanout_producer.py
+outputs $py/fanout_producer.py.out "./listener.out | remove_uuid" "./listenerX.out | remove_uuid"
+
diff --git a/qpid/cpp/examples/examples/fanout/verify_python_cpp.in b/qpid/cpp/examples/examples/fanout/verify_python_cpp.in
new file mode 100644
index 0000000000..8f9e959053
--- /dev/null
+++ b/qpid/cpp/examples/examples/fanout/verify_python_cpp.in
@@ -0,0 +1,29 @@
+==== fanout_producer.py.out
+==== listener.out | remove_uuid
+Listening
+Message: message 0
+Message: message 1
+Message: message 2
+Message: message 3
+Message: message 4
+Message: message 5
+Message: message 6
+Message: message 7
+Message: message 8
+Message: message 9
+Message: That's all, folks!
+Shutting down listener for
+==== listenerX.out | remove_uuid
+Listening
+Message: message 0
+Message: message 1
+Message: message 2
+Message: message 3
+Message: message 4
+Message: message 5
+Message: message 6
+Message: message 7
+Message: message 8
+Message: message 9
+Message: That's all, folks!
+Shutting down listener for
diff --git a/qpid/cpp/examples/examples/pub-sub/Makefile b/qpid/cpp/examples/examples/pub-sub/Makefile
new file mode 100644
index 0000000000..4b2dd52efd
--- /dev/null
+++ b/qpid/cpp/examples/examples/pub-sub/Makefile
@@ -0,0 +1,10 @@
+CXX=g++
+CXXFLAGS=
+LDFLAGS=-lqpidclient
+
+PROGRAMS=topic_listener topic_publisher
+
+all: $(PROGRAMS)
+
+clean:
+ rm -f $(PROGRAMS)
diff --git a/qpid/cpp/examples/examples/pub-sub/topic_listener.cpp b/qpid/cpp/examples/examples/pub-sub/topic_listener.cpp
new file mode 100644
index 0000000000..e5292db703
--- /dev/null
+++ b/qpid/cpp/examples/examples/pub-sub/topic_listener.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.
+ *
+ */
+
+/**
+ * topic_listener.cpp:
+ *
+ * This program is one of three programs designed to be used
+ * together. These programs use the topic exchange.
+ *
+ * topic_config_queues.cpp:
+ *
+ * Creates a queue on a broker, binding a routing key to route
+ * messages to that queue.
+ *
+ * topic_publisher.cpp:
+ *
+ * Publishes to a broker, specifying a routing key.
+ *
+ * topic_listener.cpp (this program):
+ *
+ * Reads from a queue on the broker using a message listener.
+ *
+ */
+
+#include <qpid/client/Connection.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/Message.h>
+#include <qpid/client/MessageListener.h>
+#include <qpid/client/Queue.h>
+#include <qpid/client/SubscriptionManager.h>
+
+#include <unistd.h>
+#include <cstdlib>
+#include <iostream>
+#include <set>
+
+using namespace qpid::client;
+using namespace qpid::framing;
+
+
+class Listener : public MessageListener {
+ private:
+ Session& session;
+ SubscriptionManager subscriptions;
+ public:
+ Listener(Session& session);
+ virtual void prepareQueue(std::string queue, std::string routing_key);
+ virtual void received(Message& message);
+ virtual void listen();
+ ~Listener() { };
+};
+
+
+/*
+ * Listener::Listener
+ *
+ * Subscribe to the queue, route it to a client destination for the
+ * listener. (The destination name merely identifies the destination
+ * in the listener, you can use any name as long as you use the same
+ * name for the listener).
+ */
+
+Listener::Listener(Session& session) :
+ session(session),
+ subscriptions(session)
+{
+}
+
+
+void Listener::prepareQueue(std::string queue, std::string routing_key) {
+
+ /* Create a unique queue name for this consumer by concatenating
+ * the queue name parameter with the Session ID.
+ */
+
+ queue += session.getId().str();
+ std::cout << "Declaring queue: " << queue << std::endl;
+
+ /* Declare an exclusive queue on the broker
+ */
+
+ session.queueDeclare(arg::queue=queue, arg::exclusive=true);
+
+ /* Route messages to the new queue if they match the routing key.
+ *
+ * Also route any messages to with the "control" routing key to
+ * this queue so we know when it's time to stop. A publisher sends
+ * a message with the content "That's all, Folks!", using the
+ * "control" routing key, when it is finished.
+ */
+
+ session.queueBind(arg::exchange="amq.topic", arg::queue=queue, arg::routingKey=routing_key);
+ session.queueBind(arg::exchange="amq.topic", arg::queue=queue, arg::routingKey="control");
+
+ /*
+ * subscribe to the queue using the subscription manager.
+ */
+
+ std::cout << "Subscribing to queue " << queue << std::endl;
+ subscriptions.subscribe(*this, queue);
+}
+
+void Listener::received(Message& message) {
+ std::cout << "Message: " << message.getData() << " from " << message.getDestination() << std::endl;
+
+ if (message.getData() == "That's all, folks!") {
+ std::cout << "Shutting down listener for " << message.getDestination() << std::endl;
+ subscriptions.cancel(message.getDestination());
+ }
+}
+
+void Listener::listen() {
+ // Receive messages
+ subscriptions.run();
+}
+
+int main(int argc, char** argv) {
+ const char* host = argc>1 ? argv[1] : "127.0.0.1";
+ int port = argc>2 ? atoi(argv[2]) : 5672;
+ Connection connection;
+ try {
+ connection.open(host, port);
+ Session session = connection.newSession(ASYNC);
+
+ //--------- Main body of program --------------------------------------------
+
+ // Create a listener for the session
+
+ Listener listener(session);
+
+ // Subscribe to messages on the queues we are interested in
+
+ listener.prepareQueue("usa", "usa.#");
+ listener.prepareQueue("europe", "europe.#");
+ listener.prepareQueue("news", "#.news");
+ listener.prepareQueue("weather", "#.weather");
+
+ // Wait for the broker to indicate that our queues have been created.
+ session.sync();
+
+ std::cout << "Listening for messages ..." << std::endl;
+
+ // Give up control and receive messages
+ listener.listen();
+
+
+ //-----------------------------------------------------------------------------
+
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/qpid/cpp/examples/examples/pub-sub/topic_publisher.cpp b/qpid/cpp/examples/examples/pub-sub/topic_publisher.cpp
new file mode 100644
index 0000000000..94cd3a0f56
--- /dev/null
+++ b/qpid/cpp/examples/examples/pub-sub/topic_publisher.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.
+ *
+ */
+
+
+/**
+ * topic_publisher.cpp:
+ *
+ * This program is one of three programs designed to be used
+ * together. These programs use the topic exchange.
+ *
+ * topic_config_queues.cpp:
+ *
+ * Creates a queue on a broker, binding a routing key to route
+ * messages to that queue.
+ *
+ * topic_publisher.cpp (this program):
+ *
+ * Publishes to a broker, specifying a routing key.
+ *
+ * topic_listener.cpp
+ *
+ * Reads from a queue on the broker using a message listener.
+ *
+ */
+
+
+#include <qpid/client/Connection.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/Message.h>
+
+
+#include <unistd.h>
+#include <cstdlib>
+#include <iostream>
+
+#include <sstream>
+
+using namespace qpid::client;
+using namespace qpid::framing;
+
+using std::stringstream;
+using std::string;
+
+void publish_messages(Session& session, string routing_key)
+{
+ Message message;
+
+ // Set the routing key once, we'll use the same routing key for all
+ // messages.
+
+ message.getDeliveryProperties().setRoutingKey(routing_key);
+ for (int i=0; i<5; i++) {
+ stringstream message_data;
+ message_data << "Message " << i;
+
+ message.setData(message_data.str());
+ session.messageTransfer(arg::content=message, arg::destination="amq.topic");
+ }
+
+}
+
+/*
+ * no_more_messages()
+ *
+ * Send a message to indicate that no more messages are coming.
+ * Use the 'control' routing key (see comments in topic_config_queues.cpp).
+ *
+ */
+
+void no_more_messages(Session& session)
+{
+ Message message;
+
+ message.getDeliveryProperties().setRoutingKey("control");
+ message.setData("That's all, folks!");
+ session.messageTransfer(arg::content=message, arg::destination="amq.topic");
+}
+
+int main(int argc, char** argv) {
+ const char* host = argc>1 ? argv[1] : "127.0.0.1";
+ int port = argc>2 ? atoi(argv[2]) : 5672;
+ Connection connection;
+ Message message;
+ try {
+ connection.open(host, port);
+ Session session = connection.newSession(ASYNC);
+
+ //--------- Main body of program --------------------------------------------
+
+ publish_messages(session, "usa.news");
+ publish_messages(session, "usa.weather");
+ publish_messages(session, "europe.news");
+ publish_messages(session, "europe.weather");
+
+ no_more_messages(session);
+
+ //-----------------------------------------------------------------------------
+
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/qpid/cpp/examples/examples/pub-sub/verify b/qpid/cpp/examples/examples/pub-sub/verify
new file mode 100644
index 0000000000..3589a4c9da
--- /dev/null
+++ b/qpid/cpp/examples/examples/pub-sub/verify
@@ -0,0 +1,4 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+background "Listening" ./topic_listener
+clients ./topic_publisher
+outputs ./topic_publisher.out "topic_listener.out | remove_uuid | sort"
diff --git a/qpid/cpp/examples/examples/pub-sub/verify.in b/qpid/cpp/examples/examples/pub-sub/verify.in
new file mode 100644
index 0000000000..6413c5c788
--- /dev/null
+++ b/qpid/cpp/examples/examples/pub-sub/verify.in
@@ -0,0 +1,59 @@
+==== topic_publisher.out
+==== topic_listener.out | remove_uuid | sort
+Declaring queue: europe
+Declaring queue: news
+Declaring queue: usa
+Declaring queue: weather
+Listening for messages ...
+Message: Message 0 from europe
+Message: Message 0 from europe
+Message: Message 0 from news
+Message: Message 0 from news
+Message: Message 0 from usa
+Message: Message 0 from usa
+Message: Message 0 from weather
+Message: Message 0 from weather
+Message: Message 1 from europe
+Message: Message 1 from europe
+Message: Message 1 from news
+Message: Message 1 from news
+Message: Message 1 from usa
+Message: Message 1 from usa
+Message: Message 1 from weather
+Message: Message 1 from weather
+Message: Message 2 from europe
+Message: Message 2 from europe
+Message: Message 2 from news
+Message: Message 2 from news
+Message: Message 2 from usa
+Message: Message 2 from usa
+Message: Message 2 from weather
+Message: Message 2 from weather
+Message: Message 3 from europe
+Message: Message 3 from europe
+Message: Message 3 from news
+Message: Message 3 from news
+Message: Message 3 from usa
+Message: Message 3 from usa
+Message: Message 3 from weather
+Message: Message 3 from weather
+Message: Message 4 from europe
+Message: Message 4 from europe
+Message: Message 4 from news
+Message: Message 4 from news
+Message: Message 4 from usa
+Message: Message 4 from usa
+Message: Message 4 from weather
+Message: Message 4 from weather
+Message: That's all, folks! from europe
+Message: That's all, folks! from news
+Message: That's all, folks! from usa
+Message: That's all, folks! from weather
+Shutting down listener for europe
+Shutting down listener for news
+Shutting down listener for usa
+Shutting down listener for weather
+Subscribing to queue europe
+Subscribing to queue news
+Subscribing to queue usa
+Subscribing to queue weather
diff --git a/qpid/cpp/examples/examples/pub-sub/verify_cpp_python b/qpid/cpp/examples/examples/pub-sub/verify_cpp_python
new file mode 100644
index 0000000000..ecc573eed3
--- /dev/null
+++ b/qpid/cpp/examples/examples/pub-sub/verify_cpp_python
@@ -0,0 +1,6 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+py=$PYTHON_EXAMPLES/pubsub
+background "Queues created" $py/topic_subscriber.py
+clients ./topic_publisher
+outputs ./topic_publisher.out "$py/topic_subscriber.py.out | remove_uuid64 | sort"
+
diff --git a/qpid/cpp/examples/examples/pub-sub/verify_cpp_python.in b/qpid/cpp/examples/examples/pub-sub/verify_cpp_python.in
new file mode 100644
index 0000000000..b3c9e750f5
--- /dev/null
+++ b/qpid/cpp/examples/examples/pub-sub/verify_cpp_python.in
@@ -0,0 +1,51 @@
+==== topic_publisher.out
+==== topic_subscriber.py.out | remove_uuid64 | sort
+Message 0
+Message 0
+Message 0
+Message 0
+Message 0
+Message 0
+Message 0
+Message 0
+Message 1
+Message 1
+Message 1
+Message 1
+Message 1
+Message 1
+Message 1
+Message 1
+Message 2
+Message 2
+Message 2
+Message 2
+Message 2
+Message 2
+Message 2
+Message 2
+Message 3
+Message 3
+Message 3
+Message 3
+Message 3
+Message 3
+Message 3
+Message 3
+Message 4
+Message 4
+Message 4
+Message 4
+Message 4
+Message 4
+Message 4
+Message 4
+Messages queue: europe
+Messages queue: news
+Messages queue: usa
+Messages queue: weather
+Queues created - please start the topic producer
+That's all, folks!
+That's all, folks!
+That's all, folks!
+That's all, folks!
diff --git a/qpid/cpp/examples/examples/pub-sub/verify_python_cpp b/qpid/cpp/examples/examples/pub-sub/verify_python_cpp
new file mode 100644
index 0000000000..2ddaad58c2
--- /dev/null
+++ b/qpid/cpp/examples/examples/pub-sub/verify_python_cpp
@@ -0,0 +1,6 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+py=$PYTHON_EXAMPLES/pubsub
+background "Listening" ./topic_listener
+clients $py/topic_publisher.py
+outputs $py/topic_publisher.py.out "topic_listener.out | remove_uuid | sort"
+
diff --git a/qpid/cpp/examples/examples/pub-sub/verify_python_cpp.in b/qpid/cpp/examples/examples/pub-sub/verify_python_cpp.in
new file mode 100644
index 0000000000..97fccf0a32
--- /dev/null
+++ b/qpid/cpp/examples/examples/pub-sub/verify_python_cpp.in
@@ -0,0 +1,59 @@
+==== topic_publisher.py.out
+==== topic_listener.out | remove_uuid | sort
+Declaring queue: europe
+Declaring queue: news
+Declaring queue: usa
+Declaring queue: weather
+Listening for messages ...
+Message: message 0 from europe
+Message: message 0 from europe
+Message: message 0 from news
+Message: message 0 from news
+Message: message 0 from usa
+Message: message 0 from usa
+Message: message 0 from weather
+Message: message 0 from weather
+Message: message 1 from europe
+Message: message 1 from europe
+Message: message 1 from news
+Message: message 1 from news
+Message: message 1 from usa
+Message: message 1 from usa
+Message: message 1 from weather
+Message: message 1 from weather
+Message: message 2 from europe
+Message: message 2 from europe
+Message: message 2 from news
+Message: message 2 from news
+Message: message 2 from usa
+Message: message 2 from usa
+Message: message 2 from weather
+Message: message 2 from weather
+Message: message 3 from europe
+Message: message 3 from europe
+Message: message 3 from news
+Message: message 3 from news
+Message: message 3 from usa
+Message: message 3 from usa
+Message: message 3 from weather
+Message: message 3 from weather
+Message: message 4 from europe
+Message: message 4 from europe
+Message: message 4 from news
+Message: message 4 from news
+Message: message 4 from usa
+Message: message 4 from usa
+Message: message 4 from weather
+Message: message 4 from weather
+Message: That's all, folks! from europe
+Message: That's all, folks! from news
+Message: That's all, folks! from usa
+Message: That's all, folks! from weather
+Shutting down listener for europe
+Shutting down listener for news
+Shutting down listener for usa
+Shutting down listener for weather
+Subscribing to queue europe
+Subscribing to queue news
+Subscribing to queue usa
+Subscribing to queue weather
diff --git a/qpid/cpp/examples/examples/request-response/Makefile b/qpid/cpp/examples/examples/request-response/Makefile
new file mode 100644
index 0000000000..e7ef2590d3
--- /dev/null
+++ b/qpid/cpp/examples/examples/request-response/Makefile
@@ -0,0 +1,10 @@
+CXX=g++
+CXXFLAGS=
+LDFLAGS=-lqpidclient
+
+PROGRAMS=client server
+
+all: $(PROGRAMS)
+
+clean:
+ rm -f $(PROGRAMS)
diff --git a/qpid/cpp/examples/examples/request-response/client.cpp b/qpid/cpp/examples/examples/request-response/client.cpp
new file mode 100644
index 0000000000..9f82bd9d9e
--- /dev/null
+++ b/qpid/cpp/examples/examples/request-response/client.cpp
@@ -0,0 +1,179 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+
+/**
+ * client.cpp
+ *
+ * This program is one of two programs that illustrate the
+ * request/response pattern.
+ *
+ * client.cpp (this program)
+ *
+ * Make requests of a service, print the response.
+ *
+ * service.cpp
+ *
+ * Accept requests, reverse the letters in each message, and
+ * return it as a response.
+ *
+ */
+
+
+#include <qpid/client/Connection.h>
+#include <qpid/client/Dispatcher.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/Message.h>
+#include <qpid/client/MessageListener.h>
+
+#include <unistd.h>
+#include <cstdlib>
+#include <iostream>
+
+#include <sstream>
+
+using namespace qpid::client;
+using namespace qpid::framing;
+
+class Listener : public MessageListener{
+private:
+ Session session;
+ std::string destination_name;
+ Dispatcher dispatcher;
+ int counter;
+public:
+ Listener(Session& session, string destination_name):
+ destination_name(destination_name),
+ dispatcher(session),
+ session(session),
+ counter(0)
+ {};
+
+ virtual void listen();
+ virtual void wait();
+ virtual void received(Message& message);
+ ~Listener() { };
+};
+
+
+void Listener::listen() {
+ std::cout << "Activating response queue listener for: " <<destination_name << std::endl;
+
+ session.messageSubscribe(arg::queue=destination_name, arg::destination=destination_name);
+
+ session.messageFlow(arg::destination=destination_name, arg::unit=0, arg::value=1);//messages ### Define a constant?
+ session.messageFlow(arg::destination=destination_name, arg::unit=1, arg::value=0xFFFFFFFF);//bytes ###### Define a constant?
+
+
+ dispatcher.listen(destination_name, this);
+}
+
+
+void Listener::wait() {
+ std::cout << "Waiting for all responses to arrive ..." << std::endl;
+ dispatcher.run();
+}
+
+
+void Listener::received(Message& message) {
+ std::cout << "Response: " << message.getData() << std::endl;
+
+ ++ counter;
+ if (counter > 3) {
+ std::cout << "Shutting down listener for " << destination_name << std::endl;
+ dispatcher.stop();
+ }
+}
+
+
+using std::stringstream;
+using std::string;
+
+int main(int argc, char** argv) {
+ const char* host = argc>1 ? argv[1] : "127.0.0.1";
+ int port = argc>2 ? atoi(argv[2]) : 5672;
+ Connection connection;
+ Message request;
+ try {
+ connection.open(host, port);
+ Session session = connection.newSession(ASYNC);
+
+ //--------- Main body of program --------------------------------------------
+
+ // Create a response queue so the server can send us responses
+ // to our requests. Use the client's session ID as the name
+ // of the response queue.
+
+ stringstream response_queue;
+ response_queue << "client" << session.getId();
+
+ // Use the name of the response queue as the routing key
+
+ session.queueDeclare(arg::queue=response_queue.str());
+ session.queueBind(arg::exchange="amq.direct", arg::queue=response_queue.str(), arg::routingKey=response_queue.str());
+
+ // Create a listener for the response queue and start listening.
+
+ Listener listener(session, response_queue.str());
+ listener.listen();
+
+
+ // The routing key for the request queue is simply
+ // "request", and all clients use the same routing key.
+ //
+ // Each client sends the name of their own response queue so
+ // the service knows where to route messages.
+
+ request.getDeliveryProperties().setRoutingKey("request");
+ request.getMessageProperties().setReplyTo(ReplyTo("amq.direct", response_queue.str()));
+
+ // Now send some requests ...
+
+ string s[] = {
+ "Twas brillig, and the slithy toves",
+ "Did gire and gymble in the wabe.",
+ "All mimsy were the borogroves,",
+ "And the mome raths outgrabe."
+ };
+
+
+ for (int i=0; i<4; i++) {
+ request.setData(s[i]);
+ session.messageTransfer(arg::content=request, arg::destination="amq.direct");
+ std::cout << "Request: " << s[i] << std::endl;
+ }
+
+ // And wait for any outstanding responses to arrive
+
+ listener.wait();
+
+
+ //-----------------------------------------------------------------------------
+
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/qpid/cpp/examples/examples/request-response/server.cpp b/qpid/cpp/examples/examples/request-response/server.cpp
new file mode 100644
index 0000000000..0de2ce5234
--- /dev/null
+++ b/qpid/cpp/examples/examples/request-response/server.cpp
@@ -0,0 +1,165 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+
+/**
+ * server.cpp
+ *
+ * This program is one of two programs that illustrate the
+ * request/response pattern.
+ *
+ * client.cpp
+ *
+ * Make requests of a service, print the response.
+ *
+ * server.cpp (this program)
+ *
+ * Accept requests, reverse the letters in each message, and
+ * return it as a response.
+ *
+ */
+
+
+#include <qpid/client/Connection.h>
+#include <qpid/client/Dispatcher.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/Message.h>
+#include <qpid/client/MessageListener.h>
+
+
+#include <unistd.h>
+#include <cstdlib>
+#include <iostream>
+#include <algorithm>
+
+#include <sstream>
+#include <string>
+
+using namespace qpid::client;
+using namespace qpid::framing;
+using std::stringstream;
+using std::string;
+
+class Listener : public MessageListener{
+private:
+ std::string destination_name;
+ Dispatcher dispatcher;
+ Session session;
+public:
+ Listener(Session& session, string destination_name):
+ destination_name(destination_name),
+ dispatcher(session),
+ session(session)
+ {};
+
+ virtual void listen();
+ virtual void received(Message& message);
+ virtual void wait();
+ ~Listener() { };
+};
+
+
+void Listener::listen() {
+ std::cout << "Activating request queue listener for: " <<destination_name << std::endl;
+
+ session.messageSubscribe(arg::queue=destination_name, arg::destination=destination_name);
+
+ // ##### Should not be needed. Sigh.
+ session.messageFlow(arg::destination=destination_name, arg::unit=0, arg::value=1);//messages ### Define a constant?
+ session.messageFlow(arg::destination=destination_name, arg::unit=1, arg::value=0xFFFFFFFF);//bytes ###### Define a constant?
+
+ dispatcher.listen(destination_name, this);
+}
+
+
+void Listener::wait() {
+ std::cout << "Waiting for requests" << std::endl;
+ dispatcher.run();
+}
+
+
+void Listener::received(Message& request) {
+
+ Message response;
+
+ // Get routing key for response from the request's replyTo property
+
+ string routingKey;
+
+ if (request.getMessageProperties().hasReplyTo()) {
+ routingKey = request.getMessageProperties().getReplyTo().getRoutingKey();
+ } else {
+ std::cout << "Error: " << "No routing key for request (" << request.getData() << ")" << std::endl;
+ return;
+ }
+
+ std::cout << "Request: " << request.getData() << " (" <<routingKey << ")" << std::endl;
+
+ // Transform message content to upper case
+ std::string s = request.getData();
+ std::transform (s.begin(), s.end(), s.begin(), toupper);
+ response.setData(s);
+
+ // Send it back to the user
+ response.getDeliveryProperties().setRoutingKey(routingKey);
+ session.messageTransfer(arg::content=response, arg::destination="amq.direct");
+}
+
+
+int main(int argc, char** argv) {
+ const char* host = argc>1 ? argv[1] : "127.0.0.1";
+ int port = argc>2 ? atoi(argv[2]) : 5672;
+ Connection connection;
+ Message message;
+ try {
+ connection.open(host, port);
+ Session session = connection.newSession(ASYNC);
+
+ //--------- Main body of program --------------------------------------------
+
+ // Create a request queue for clients to use when making
+ // requests.
+
+ string request_queue = "request";
+
+ // Use the name of the request queue as the routing key
+
+ session.queueDeclare(arg::queue=request_queue);
+ session.queueBind(arg::exchange="amq.direct", arg::queue=request_queue, arg::routingKey=request_queue);
+
+ // Create a listener for the request queue and start listening.
+
+ Listener listener(session, request_queue);
+ listener.listen();
+ listener.wait();
+
+
+ //-----------------------------------------------------------------------------
+
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/qpid/cpp/examples/examples/request-response/verify b/qpid/cpp/examples/examples/request-response/verify
new file mode 100644
index 0000000000..76007ff8d2
--- /dev/null
+++ b/qpid/cpp/examples/examples/request-response/verify
@@ -0,0 +1,5 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+background "Waiting" ./server
+clients ./client
+kill %% # Must kill the server.
+outputs "./client.out | remove_uuid" "server.out | remove_uuid"
diff --git a/qpid/cpp/examples/examples/request-response/verify.in b/qpid/cpp/examples/examples/request-response/verify.in
new file mode 100644
index 0000000000..7925dc5671
--- /dev/null
+++ b/qpid/cpp/examples/examples/request-response/verify.in
@@ -0,0 +1,19 @@
+==== client.out | remove_uuid
+Activating response queue listener for: client
+Request: Twas brillig, and the slithy toves
+Request: Did gire and gymble in the wabe.
+Request: All mimsy were the borogroves,
+Request: And the mome raths outgrabe.
+Waiting for all responses to arrive ...
+Response: TWAS BRILLIG, AND THE SLITHY TOVES
+Response: DID GIRE AND GYMBLE IN THE WABE.
+Response: ALL MIMSY WERE THE BOROGROVES,
+Response: AND THE MOME RATHS OUTGRABE.
+Shutting down listener for client
+==== server.out | remove_uuid
+Activating request queue listener for: request
+Waiting for requests
+Request: Twas brillig, and the slithy toves (client)
+Request: Did gire and gymble in the wabe. (client)
+Request: All mimsy were the borogroves, (client)
+Request: And the mome raths outgrabe. (client)
diff --git a/qpid/cpp/examples/examples/request-response/verify_cpp_python b/qpid/cpp/examples/examples/request-response/verify_cpp_python
new file mode 100644
index 0000000000..9d71d51c37
--- /dev/null
+++ b/qpid/cpp/examples/examples/request-response/verify_cpp_python
@@ -0,0 +1,5 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+background "Request server running" $PYTHON_EXAMPLES/request-response/server.py
+clients ./client
+kill %% # Must kill the server.
+outputs "./client.out | remove_uuid" "$PYTHON_EXAMPLES/request-response/server.py.out | remove_uuid64"
diff --git a/qpid/cpp/examples/examples/request-response/verify_cpp_python.in b/qpid/cpp/examples/examples/request-response/verify_cpp_python.in
new file mode 100644
index 0000000000..280484bd2a
--- /dev/null
+++ b/qpid/cpp/examples/examples/request-response/verify_cpp_python.in
@@ -0,0 +1,15 @@
+==== client.out | remove_uuid
+Activating response queue listener for: client
+Request: Twas brillig, and the slithy toves
+Request: Did gire and gymble in the wabe.
+Request: All mimsy were the borogroves,
+Request: And the mome raths outgrabe.
+Waiting for all responses to arrive ...
+Response: TWAS BRILLIG, AND THE SLITHY TOVES
+Response: DID GIRE AND GYMBLE IN THE WABE.
+Response: ALL MIMSY WERE THE BOROGROVES,
+Response: AND THE MOME RATHS OUTGRABE.
+Shutting down listener for client
+==== server.py.out | remove_uuid64
+Request server running - run your client now.
+(Times out after 100 seconds ...)
diff --git a/qpid/cpp/examples/examples/request-response/verify_python_cpp b/qpid/cpp/examples/examples/request-response/verify_python_cpp
new file mode 100644
index 0000000000..9f3f1caaf4
--- /dev/null
+++ b/qpid/cpp/examples/examples/request-response/verify_python_cpp
@@ -0,0 +1,5 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+background "Waiting" ./server
+clients $PYTHON_EXAMPLES/request-response/client.py
+kill %% # Must kill the server.
+outputs "$PYTHON_EXAMPLES/request-response/client.py.out | remove_uuid64" "server.out | remove_uuid64"
diff --git a/qpid/cpp/examples/examples/request-response/verify_python_cpp.in b/qpid/cpp/examples/examples/request-response/verify_python_cpp.in
new file mode 100644
index 0000000000..7718d54973
--- /dev/null
+++ b/qpid/cpp/examples/examples/request-response/verify_python_cpp.in
@@ -0,0 +1,18 @@
+==== client.py.out | remove_uuid64
+Request: Twas brilling, and the slithy toves
+Request: Did gyre and gimble in the wabe.
+Request: All mimsy were the borogroves,
+Request: And the mome raths outgrabe.
+Messages queue: ReplyTo:
+Response: TWAS BRILLING, AND THE SLITHY TOVES
+Response: DID GYRE AND GIMBLE IN THE WABE.
+Response: ALL MIMSY WERE THE BOROGROVES,
+Response: AND THE MOME RATHS OUTGRABE.
+No more messages!
+==== server.out | remove_uuid64
+Activating request queue listener for: request
+Waiting for requests
+Request: Twas brilling, and the slithy toves (ReplyTo:)
+Request: Did gyre and gimble in the wabe. (ReplyTo:)
+Request: All mimsy were the borogroves, (ReplyTo:)
+Request: And the mome raths outgrabe. (ReplyTo:)
diff --git a/qpid/cpp/examples/verify b/qpid/cpp/examples/verify
new file mode 100755
index 0000000000..251097930e
--- /dev/null
+++ b/qpid/cpp/examples/verify
@@ -0,0 +1,85 @@
+#!/bin/sh
+# Driver script to verify installed examples (also used for build tests.)
+#
+# Usage: verify example_dir [ example_dir ...]
+# Where each example_dir must contain a verify sub-script to include.
+#
+# If $QPIDD is set, run a private QPIDD and use it.
+# If $QPID_HOST or $QPID_PORT are set, use them to connect.
+#
+
+export QPID_DATA_DIR=
+
+cleanup() {
+ test -n "$QPIDD" && $QPIDD -q # Private broker
+ kill %% > /dev/null 2>&1 # Leftover background jobs
+}
+
+trap cleanup EXIT
+
+ARGS="${QPID_HOST:-localhost} $QPID_PORT"
+
+outfile() {
+ file=$1
+ while [ -f $file.out ]; do file="${file}X"; done
+ echo $file.out
+ }
+
+fail() { test -n "$*" && echo $* 1>&2 ; FAIL=1; return 1; }
+
+client() { "$@" $ARGS > `outfile $*` || fail; }
+
+clients() { for cmd in "$@"; do client $cmd; done; }
+
+waitfor() { until grep -a -l "$2" $1 >/dev/null 2>&1 ; do sleep 1 ; done ; }
+
+background() {
+ pattern=$1; shift
+ out=`outfile $*`
+ eval "$* $ARGS > $out &" || { fail; return 1; }
+ waitfor $out "$pattern"
+}
+
+name() {
+ for x in $*; do name="$name `basename $x`"; done
+ echo $name;
+}
+
+outputs() {
+ wait 2> /dev/null # Wait for all backgroud processes to complete
+ rm -f $script.out
+ for f in "$@"; do
+ { echo "==== `name $f`"; eval "cat $f"; } >> $script.out || fail
+ done
+}
+
+verify() {
+ FAIL=
+ if [ -d $1 ]; then dir=$1; script=verify;
+ else dir=`dirname $1`; script=`basename $1`; fi
+ cd $dir || return 1
+ rm -f *.out
+ { source ./$script && diff -ac $script.out $script.in ; } || fail
+ test -z "$FAIL" && rm -f *.out
+ return $FAIL
+}
+
+HEX="[a-fA-F0-9]"
+remove_uuid() {
+ sed "s/$HEX\{8\}-$HEX\{4\}-$HEX\{4\}-$HEX\{4\}-$HEX\{12\}//g" $*
+}
+remove_uuid64() {
+ sed 's/[-A-Za-z0-9_]\{22\}==//g' $*
+}
+
+# Start private broker if QPIDD is set.
+if [ -n "$QPIDD" ] ; then
+ export QPID_PORT=`$QPIDD -dp0` || { echo "Cannot start $QPIDD" ; exit 1; }
+ trap "$QPIDD -q" EXIT
+fi
+
+for example in "$@"; do
+ echo "== $example "
+ if ( verify $example; ) then echo "PASS"; else echo "FAIL"; RET=1; fi
+ done
+exit $RET
diff --git a/qpid/cpp/examples/verify_all b/qpid/cpp/examples/verify_all
new file mode 100755
index 0000000000..5501239021
--- /dev/null
+++ b/qpid/cpp/examples/verify_all
@@ -0,0 +1,23 @@
+#!/bin/sh
+# Verify all C++/python example combinations.
+#
+
+srcdir=$1 ;
+verify=`dirname $0`/verify
+qpidd=../src/qpidd
+python=$srcdir/python
+
+trap "$qpidd -q" exit
+export QPID_PORT=`$qpidd -dp0 --data-dir ""`
+export PYTHON_EXAMPLES=$python/examples
+export PYTHONPATH=$python:$PYTHONPATH
+export AMQP_SPEC=$srcdir/specs/amqp.0-10-preview.xml
+
+test -d $PYTHON_EXAMPLES || echo "Warning: not verifying python examples, $PYTHON_EXAMPLES not found"
+find="find examples"
+test -d $PYTHON_EXAMPLES && find="$find $PYTHON_EXAMPLES"
+find="$find -name verify"
+test -d $PYTHON_EXAMPLES && \
+ find="$find -o -name verify_cpp_python -o -name verify_python_cpp"
+$verify `$find`
+
diff --git a/qpid/cpp/m4/clock_time.m4 b/qpid/cpp/m4/clock_time.m4
new file mode 100644
index 0000000000..227a5978e5
--- /dev/null
+++ b/qpid/cpp/m4/clock_time.m4
@@ -0,0 +1,30 @@
+# clock_time.m4 serial 8
+dnl Copyright (C) 2002-2006 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+# Check for clock_gettime and clock_settime, and set LIB_CLOCK_GETTIME.
+# For a program named, say foo, you should add a line like the following
+# in the corresponding Makefile.am file:
+# foo_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME)
+
+AC_DEFUN([gl_CLOCK_TIME],
+[
+ dnl Persuade glibc and Solaris <time.h> to declare these functions.
+ AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+
+ # Solaris 2.5.1 needs -lposix4 to get the clock_gettime function.
+ # Solaris 7 prefers the library name -lrt to the obsolescent name -lposix4.
+
+ # Save and restore LIBS so e.g., -lrt, isn't added to it. Otherwise, *all*
+ # programs in the package would end up linked with that potentially-shared
+ # library, inducing unnecessary run-time overhead.
+ gl_saved_libs=$LIBS
+ AC_SEARCH_LIBS(clock_gettime, [rt posix4],
+ [test "$ac_cv_search_clock_gettime" = "none required" ||
+ LIB_CLOCK_GETTIME=$ac_cv_search_clock_gettime])
+ AC_SUBST([LIB_CLOCK_GETTIME])
+ AC_CHECK_FUNCS(clock_gettime clock_settime)
+ LIBS=$gl_saved_libs
+])
diff --git a/qpid/cpp/m4/compiler-flags.m4 b/qpid/cpp/m4/compiler-flags.m4
new file mode 100644
index 0000000000..01cb728f02
--- /dev/null
+++ b/qpid/cpp/m4/compiler-flags.m4
@@ -0,0 +1,23 @@
+# serial 3
+# Find valid warning flags for the C Compiler. -*-Autoconf-*-
+dnl Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+dnl Written by Jesse Thilo.
+
+AC_DEFUN([gl_COMPILER_FLAGS],
+ [AC_MSG_CHECKING(whether compiler accepts $1)
+ AC_SUBST(COMPILER_FLAGS)
+ ac_save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $1"
+ ac_save_CXXFLAGS="$CXXFLAGS"
+ CXXFLAGS="$CXXFLAGS $1"
+ AC_TRY_COMPILE(,
+ [int x;],
+ COMPILER_FLAGS="$COMPILER_FLAGS $1"
+ AC_MSG_RESULT(yes),
+ AC_MSG_RESULT(no))
+ CFLAGS="$ac_save_CFLAGS"
+ CXXFLAGS="$ac_save_CXXFLAGS"
+ ])
diff --git a/qpid/cpp/m4/cppunit.m4 b/qpid/cpp/m4/cppunit.m4
new file mode 100644
index 0000000000..f009086f9d
--- /dev/null
+++ b/qpid/cpp/m4/cppunit.m4
@@ -0,0 +1,89 @@
+dnl
+dnl AM_PATH_CPPUNIT(MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl
+AC_DEFUN([AM_PATH_CPPUNIT],
+[
+
+AC_ARG_WITH(cppunit-prefix,[ --with-cppunit-prefix=PFX Prefix where CppUnit is installed (optional)],
+ cppunit_config_prefix="$withval", cppunit_config_prefix="")
+AC_ARG_WITH(cppunit-exec-prefix,[ --with-cppunit-exec-prefix=PFX Exec prefix where CppUnit is installed (optional)],
+ cppunit_config_exec_prefix="$withval", cppunit_config_exec_prefix="")
+
+ if test x$cppunit_config_exec_prefix != x ; then
+ cppunit_config_args="$cppunit_config_args --exec-prefix=$cppunit_config_exec_prefix"
+ if test x${CPPUNIT_CONFIG+set} != xset ; then
+ CPPUNIT_CONFIG=$cppunit_config_exec_prefix/bin/cppunit-config
+ fi
+ fi
+ if test x$cppunit_config_prefix != x ; then
+ cppunit_config_args="$cppunit_config_args --prefix=$cppunit_config_prefix"
+ if test x${CPPUNIT_CONFIG+set} != xset ; then
+ CPPUNIT_CONFIG=$cppunit_config_prefix/bin/cppunit-config
+ fi
+ fi
+
+ AC_PATH_PROG(CPPUNIT_CONFIG, cppunit-config, no)
+ cppunit_version_min=$1
+
+ AC_MSG_CHECKING(for Cppunit - version >= $cppunit_version_min)
+ no_cppunit=""
+ if test "$CPPUNIT_CONFIG" = "no" ; then
+ AC_MSG_RESULT(no)
+ no_cppunit=yes
+ else
+ CPPUNIT_CFLAGS=`$CPPUNIT_CONFIG --cflags`
+ CPPUNIT_LIBS=`$CPPUNIT_CONFIG --libs`
+ cppunit_version=`$CPPUNIT_CONFIG --version`
+
+ cppunit_major_version=`echo $cppunit_version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+ cppunit_minor_version=`echo $cppunit_version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+ cppunit_micro_version=`echo $cppunit_version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+
+ cppunit_major_min=`echo $cppunit_version_min | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+ if test "x${cppunit_major_min}" = "x" ; then
+ cppunit_major_min=0
+ fi
+
+ cppunit_minor_min=`echo $cppunit_version_min | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+ if test "x${cppunit_minor_min}" = "x" ; then
+ cppunit_minor_min=0
+ fi
+
+ cppunit_micro_min=`echo $cppunit_version_min | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+ if test "x${cppunit_micro_min}" = "x" ; then
+ cppunit_micro_min=0
+ fi
+
+ cppunit_version_proper=`expr \
+ $cppunit_major_version \> $cppunit_major_min \| \
+ $cppunit_major_version \= $cppunit_major_min \& \
+ $cppunit_minor_version \> $cppunit_minor_min \| \
+ $cppunit_major_version \= $cppunit_major_min \& \
+ $cppunit_minor_version \= $cppunit_minor_min \& \
+ $cppunit_micro_version \>= $cppunit_micro_min `
+
+ if test "$cppunit_version_proper" = "1" ; then
+ AC_MSG_RESULT([$cppunit_major_version.$cppunit_minor_version.$cppunit_micro_version])
+ else
+ AC_MSG_RESULT(no)
+ no_cppunit=yes
+ fi
+ fi
+
+ if test "x$no_cppunit" = x ; then
+ ifelse([$2], , :, [$2])
+ else
+ CPPUNIT_CFLAGS=""
+ CPPUNIT_LIBS=""
+ ifelse([$3], , :, [$3])
+ fi
+
+ AC_SUBST(CPPUNIT_CFLAGS)
+ AC_SUBST(CPPUNIT_LIBS)
+])
diff --git a/qpid/cpp/m4/extensions.m4 b/qpid/cpp/m4/extensions.m4
new file mode 100644
index 0000000000..143a9e5403
--- /dev/null
+++ b/qpid/cpp/m4/extensions.m4
@@ -0,0 +1,58 @@
+# serial 4 -*- Autoconf -*-
+# Enable extensions on systems that normally disable them.
+
+# Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This definition of AC_USE_SYSTEM_EXTENSIONS is stolen from CVS
+# Autoconf. Perhaps we can remove this once we can assume Autoconf
+# 2.61 or later everywhere, but since CVS Autoconf mutates rapidly
+# enough in this area it's likely we'll need to redefine
+# AC_USE_SYSTEM_EXTENSIONS for quite some time.
+
+# AC_USE_SYSTEM_EXTENSIONS
+# ------------------------
+# Enable extensions on systems that normally disable them,
+# typically due to standards-conformance issues.
+AC_DEFUN([AC_USE_SYSTEM_EXTENSIONS],
+[
+ AC_BEFORE([$0], [AC_COMPILE_IFELSE])
+ AC_BEFORE([$0], [AC_RUN_IFELSE])
+
+ AC_REQUIRE([AC_GNU_SOURCE])
+ AC_REQUIRE([AC_AIX])
+ AC_REQUIRE([AC_MINIX])
+
+ AH_VERBATIM([__EXTENSIONS__],
+[/* Enable extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif])
+ AC_CACHE_CHECK([whether it is safe to define __EXTENSIONS__],
+ [ac_cv_safe_to_define___extensions__],
+ [AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM([
+# define __EXTENSIONS__ 1
+ AC_INCLUDES_DEFAULT])],
+ [ac_cv_safe_to_define___extensions__=yes],
+ [ac_cv_safe_to_define___extensions__=no])])
+ test $ac_cv_safe_to_define___extensions__ = yes &&
+ AC_DEFINE([__EXTENSIONS__])
+ AC_DEFINE([_POSIX_PTHREAD_SEMANTICS])
+ AC_DEFINE([_TANDEM_SOURCE])
+])
+
+# gl_USE_SYSTEM_EXTENSIONS
+# ------------------------
+# Enable extensions on systems that normally disable them,
+# typically due to standards-conformance issues.
+AC_DEFUN([gl_USE_SYSTEM_EXTENSIONS],
+ [AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])])
diff --git a/qpid/cpp/make-dist b/qpid/cpp/make-dist
new file mode 100755
index 0000000000..c23cad63a1
--- /dev/null
+++ b/qpid/cpp/make-dist
@@ -0,0 +1,83 @@
+#!/bin/bash
+#
+# Temporary hack for producing a binary dev distribution.
+# Includes regular stuff from 'make install' + examples and headers.
+#
+# TODO: Also include debug libraries.
+#
+
+Usage() {
+ echo "usage: $0 [release-version]
+ release-version e.g. 1.0M1 (defaults to the svn revision)" >&2
+ exit 2
+}
+
+if [[ $# -eq 1 ]]; then
+ [[ $1 == "-?" ]] && Usage
+ version=$1
+elif [[ $# -ne 0 ]]; then
+ Usage
+else
+ # Default the version to the svn revision
+ if which svn >/dev/null 2>&1; then
+ svnRevision=$(svn info | grep ^Revision: | awk '{print $2}')
+ version=r${svnRevision}
+ else
+ echo "You need to have svn in your PATH or specify a release-version"
+ exit 2
+ fi
+fi
+
+releaseName=qpid-cpp-dev-${version}-$(uname -s)-$(uname -p)
+releaseDir=release/$releaseName
+
+if [[ -d $releaseDir ]]; then
+ echo "$releaseDir already exists"
+ exit 2
+fi
+
+# Copy bin.
+mkdir -p $releaseDir/bin
+cp -r src/.libs/* ${releaseDir}/bin
+
+# Copy libs.
+mkdir -p $releaseDir/lib
+cp lib/broker/.libs/lib* lib/common/.libs/lib* lib/client/.libs/lib* \
+ $releaseDir/lib
+
+# Copy gen include files.
+find gen -name \*.h | while read file; do
+ destFile=${releaseDir}/include/$file
+ baseDir=$(dirname $destFile)
+ mkdir -p $baseDir
+ cp $file $destFile
+done
+
+# Copy in lib include files.
+(
+ cd lib; find . -name \*.h | while read file; do
+ destFile=../${releaseDir}/include/$file
+ baseDir=$(dirname $destFile)
+ mkdir -p $baseDir
+ cp $file $destFile
+ done
+)
+
+# Copy non-cppunit tests as examples.
+mkdir -p $releaseDir/examples
+for file in tests/*.cpp; do
+ if grep CppUnit $file >/dev/null; then
+ echo Skipping cppunit file $file
+ else
+ cp $file $releaseDir/examples
+ fi
+done
+
+# Copy Makefile and README for examples.
+cp tests/examples.Makefile $releaseDir/examples/Makefile
+cp tests/examples.README $releaseDir/examples/README
+
+cd release
+tar=$releaseName.tar
+tar cvf $tar $releaseName
+bzip2 $tar
diff --git a/qpid/cpp/managementgen/generate.py b/qpid/cpp/managementgen/generate.py
new file mode 100755
index 0000000000..e1c01de9b0
--- /dev/null
+++ b/qpid/cpp/managementgen/generate.py
@@ -0,0 +1,269 @@
+#!/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.
+#
+
+from xml.dom.minidom import parse, parseString, Node
+from cStringIO import StringIO
+from stat import *
+from errno import *
+import os
+import os.path
+import filecmp
+
+class Template:
+ """
+ Expandable File Template - This class is instantiated each time a
+ template is to be expanded. It is instantiated with the "filename"
+ which is the full path to the template file and the "handler" which
+ is an object that is responsible for storing variables (setVariable)
+ and expanding tags (substHandler).
+ """
+ def __init__ (self, filename, handler):
+ self.filename = filename
+ self.handler = handler
+ self.handler.initExpansion ()
+
+ def expandLine (self, line, stream, object):
+ cursor = 0
+ while 1:
+ sub = line.find ("/*MGEN:", cursor)
+ if sub == -1:
+ stream.write (line[cursor:len (line)])
+ return
+
+ subend = line.find("*/", sub)
+ stream.write (line[cursor:sub])
+ cursor = subend + 2
+
+ tag = line[sub:subend]
+ equalPos = tag.find ("=")
+ if equalPos == -1:
+ dotPos = tag.find (".")
+ if dotPos == -1:
+ raise ValueError ("Invalid tag: %s" % tag)
+ tagObject = tag[7:dotPos]
+ tagName = tag[dotPos + 1:len (tag)]
+ self.handler.substHandler (object, stream, tagObject, tagName)
+ else:
+ tagKey = tag[7:equalPos]
+ tagVal = tag[equalPos + 1:len (tag)]
+ self.handler.setVariable (tagKey, tagVal)
+
+ def expand (self, object):
+ fd = open (self.filename)
+ stream = StringIO ()
+
+ for line in fd:
+ self.expandLine (line, stream, object)
+ fd.close ()
+
+ return stream
+
+
+class Makefile:
+ """ Object representing a makefile fragment """
+ def __init__ (self, filelists, templateFiles):
+ self.filelists = filelists
+ self.templateFiles = templateFiles
+
+ def genGenSources (self, stream, variables):
+ mdir = variables["mgenDir"]
+ sdir = variables["specDir"]
+ stream.write (mdir + "/main.py \\\n")
+ stream.write (" " + mdir + "/generate.py \\\n")
+ stream.write (" " + mdir + "/schema.py \\\n")
+ stream.write (" " + sdir + "/management-types.xml \\\n")
+ stream.write (" " + sdir + "/management-schema.xml \\\n")
+ first = True
+ for template in self.templateFiles:
+ if first:
+ first = False
+ stream.write (" ")
+ else:
+ stream.write (" \\\n ")
+ stream.write (mdir + "/templates/" + template)
+
+ def genGenCppFiles (self, stream, variables):
+ first = True
+ for file in self.filelists["cpp"]:
+ if first:
+ first = False
+ else:
+ stream.write (" \\\n ")
+ stream.write (file)
+
+ def genGenHFiles (self, stream, variables):
+ first = True
+ for file in self.filelists["h"]:
+ if first:
+ first = False
+ else:
+ stream.write (" \\\n ")
+ stream.write (file)
+
+
+class Generator:
+ """
+ This class manages code generation using template files. It is instantiated
+ once for an entire code generation session.
+ """
+ def createPath (self, path):
+ exists = True
+ try:
+ mode = os.stat (path)[ST_MODE]
+ except OSError, (err,text):
+ if err == ENOENT:
+ exists = False
+ else:
+ raise
+ if exists and not S_ISDIR (mode):
+ raise ValueError ("path is not directory: %s" % path)
+ if not exists:
+ pair = os.path.split (path)
+ self.createPath (pair[0])
+ os.mkdir (path)
+
+ def normalize (self, path):
+ newpath = os.path.normcase (os.path.normpath (path))
+ self.createPath (newpath)
+ return newpath + "/"
+
+ def __init__ (self, destDir, templateDir):
+ self.dest = self.normalize (destDir)
+ self.input = self.normalize (templateDir)
+ self.filelists = {}
+ self.filelists["h"] = []
+ self.filelists["cpp"] = []
+ self.filelists["mk"] = []
+ self.templateFiles = []
+ self.variables = {}
+
+ def genDisclaimer (self, stream, variables):
+ prefix = variables["commentPrefix"]
+ stream.write (prefix + " This source file was created by a code generator.\n")
+ stream.write (prefix + " Please do not edit.")
+
+ def fileExt (self, path):
+ dot = path.rfind (".")
+ if dot == -1:
+ return ""
+ return path[dot + 1:]
+
+ def writeIfChanged (self, stream, target, force=False):
+ ext = self.fileExt (target)
+ self.filelists[ext].append (target)
+ tempFile = self.dest + "gen.tmp"
+ fd = open (tempFile, "w")
+ fd.write (stream.getvalue ())
+ fd.close ()
+
+ try:
+ if not force and filecmp.cmp (target, tempFile):
+ os.remove (tempFile)
+ return
+ except:
+ pass
+
+ try:
+ os.remove (target)
+ except:
+ pass
+
+ os.rename (tempFile, target)
+ print "Generated:", target
+
+ def targetPackageFile (self, schema, templateFile):
+ dot = templateFile.find(".")
+ if dot == -1:
+ raise ValueError ("Invalid template file name %s" % templateFile)
+ extension = templateFile[dot:len (templateFile)]
+ path = self.dest + "Package" + schema.getPackageName().capitalize() + extension
+ return path
+
+ def targetClassFile (self, _class, templateFile):
+ dot = templateFile.find(".")
+ if dot == -1:
+ raise ValueError ("Invalid template file name %s" % templateFile)
+ extension = templateFile[dot:len (templateFile)]
+ path = self.dest + _class.getName ().capitalize () + extension
+ return path
+
+ def targetMethodFile (self, method, templateFile):
+ """ Return the file name for a method file """
+ dot = templateFile.rfind(".")
+ if dot == -1:
+ raise ValueError ("Invalid template file name %s" % templateFile)
+ extension = templateFile[dot:]
+ path = self.dest + "Args" + method.getFullName () + extension
+ return path
+
+ def initExpansion (self):
+ self.variables = {}
+
+ def substHandler (self, object, stream, tagObject, tag):
+ if tagObject == "Root":
+ obj = "self"
+ else:
+ obj = "object" # MUST be the same as the 2nd formal parameter
+
+ call = obj + ".gen" + tag + "(stream, self.variables)"
+ eval (call)
+
+ def setVariable (self, key, value):
+ self.variables[key] = value
+
+ def makeClassFiles (self, templateFile, schema, force=False):
+ """ Generate an expanded template per schema class """
+ classes = schema.getClasses ()
+ template = Template (self.input + templateFile, self)
+ self.templateFiles.append (templateFile)
+ for _class in classes:
+ target = self.targetClassFile (_class, templateFile)
+ stream = template.expand (_class)
+ self.writeIfChanged (stream, target, force)
+
+ def makeMethodFiles (self, templateFile, schema, force=False):
+ """ Generate an expanded template per method-with-arguments """
+ classes = schema.getClasses ()
+ template = Template (self.input + templateFile, self)
+ self.templateFiles.append (templateFile)
+ for _class in classes:
+ methods = _class.getMethods ()
+ for method in methods:
+ if method.getArgCount () > 0:
+ target = self.targetMethodFile (method, templateFile)
+ stream = template.expand (method)
+ self.writeIfChanged (stream, target, force)
+
+ def makePackageFile (self, templateFile, schema, force=False):
+ """ Generate a package-specific file """
+ template = Template (self.input + templateFile, self)
+ self.templateFiles.append (templateFile)
+ target = self.targetPackageFile (schema, templateFile)
+ stream = template.expand (schema)
+ self.writeIfChanged (stream, target, force)
+
+ def makeSingleFile (self, templateFile, target, force=False):
+ """ Generate a single expanded template """
+ makefile = Makefile (self.filelists, self.templateFiles)
+ template = Template (self.input + templateFile, self)
+ self.templateFiles.append (templateFile)
+ stream = template.expand (makefile)
+ self.writeIfChanged (stream, target, force)
diff --git a/qpid/cpp/managementgen/main.py b/qpid/cpp/managementgen/main.py
new file mode 100755
index 0000000000..87ef3d5298
--- /dev/null
+++ b/qpid/cpp/managementgen/main.py
@@ -0,0 +1,58 @@
+#!/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.
+#
+
+from schema import PackageSchema, SchemaClass
+from generate import Generator
+from optparse import OptionParser
+
+# Set command line options
+usage = "usage: %prog [options] schema-document type-document template-directory out-directory"
+parser = OptionParser (usage=usage)
+parser.add_option ("-m", "--makefile", dest="makefile", metavar="FILE",
+ help="Makefile fragment")
+parser.add_option ("-i", "--include-prefix", dest="include_prefix", metavar="PATH",
+ default="qpid/management/",
+ help="Prefix for #include of generated headers in generated source, default: qpid/management/")
+
+(opts, args) = parser.parse_args ()
+
+if len (args) < 4:
+ parser.error ("Too few arguments")
+
+schemafile = args[0]
+typefile = args[1]
+templatedir = args[2]
+outdir = args[3]
+
+if opts.include_prefix == ".":
+ opts.include_prefix = None
+
+gen = Generator (outdir, templatedir)
+schema = PackageSchema (typefile, schemafile, opts)
+
+gen.makeClassFiles ("Class.h", schema)
+gen.makeClassFiles ("Class.cpp", schema)
+gen.makeMethodFiles ("Args.h", schema)
+gen.makePackageFile ("Package.h", schema)
+gen.makePackageFile ("Package.cpp", schema)
+
+if opts.makefile != None:
+ gen.makeSingleFile ("Makefile.mk", opts.makefile, force=True)
diff --git a/qpid/cpp/managementgen/schema.py b/qpid/cpp/managementgen/schema.py
new file mode 100755
index 0000000000..7e4a91814f
--- /dev/null
+++ b/qpid/cpp/managementgen/schema.py
@@ -0,0 +1,911 @@
+#!/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.
+#
+
+from xml.dom.minidom import parse, parseString, Node
+from cStringIO import StringIO
+import md5
+
+#=====================================================================================
+#
+#=====================================================================================
+class SchemaType:
+ def __init__ (self, node):
+ self.name = None
+ self.base = None
+ self.cpp = None
+ self.encode = None
+ self.decode = None
+ self.style = "normal"
+ self.accessor = None
+ self.init = "0"
+
+ attrs = node.attributes
+ for idx in range (attrs.length):
+ key = attrs.item(idx).nodeName
+ val = attrs.item(idx).nodeValue
+ if key == 'name':
+ self.name = val
+
+ elif key == 'base':
+ self.base = val
+
+ elif key == 'cpp':
+ self.cpp = val
+
+ elif key == 'encode':
+ self.encode = val
+
+ elif key == 'decode':
+ self.decode = val
+
+ elif key == 'style':
+ self.style = val
+
+ elif key == 'accessor':
+ self.accessor = val
+
+ elif key == 'init':
+ self.init = val
+
+ else:
+ raise ValueError ("Unknown attribute in type '%s'" % key)
+
+ if self.name == None or self.base == None or self.cpp == None or \
+ self.encode == None or self.decode == None:
+ raise ValueError ("Missing required attribute(s) in type")
+
+ def getName (self):
+ return self.name
+
+ def genAccessor (self, stream, varName, changeFlag = None):
+ if self.accessor == "direct":
+ stream.write (" inline void set_" + varName + " (" + self.cpp + " val){\n");
+ stream.write (" sys::RWlock::ScopedWlock writeLock (accessLock);\n")
+ if self.style != "mma":
+ stream.write (" " + varName + " = val;\n");
+ if self.style == "wm":
+ stream.write (" if (" + varName + "Low > val)\n")
+ stream.write (" " + varName + "Low = val;\n")
+ stream.write (" if (" + varName + "High < val)\n")
+ stream.write (" " + varName + "High = val;\n")
+ if self.style == "mma":
+ stream.write (" " + varName + "Count++;\n")
+ stream.write (" " + varName + "Total += val;\n")
+ stream.write (" if (" + varName + "Min > val)\n")
+ stream.write (" " + varName + "Min = val;\n")
+ stream.write (" if (" + varName + "Max < val)\n")
+ stream.write (" " + varName + "Max = val;\n")
+ if changeFlag != None:
+ stream.write (" " + changeFlag + " = true;\n")
+ stream.write (" }\n");
+ elif self.accessor == "counter":
+ stream.write (" inline void inc_" + varName + " (" + self.cpp + " by = 1){\n");
+ stream.write (" sys::RWlock::ScopedWlock writeLock (accessLock);\n")
+ stream.write (" " + varName + " += by;\n")
+ if self.style == "wm":
+ stream.write (" if (" + varName + "High < " + varName + ")\n")
+ stream.write (" " + varName + "High = " + varName + ";\n")
+ if changeFlag != None:
+ stream.write (" " + changeFlag + " = true;\n")
+ stream.write (" }\n");
+ stream.write (" inline void dec_" + varName + " (" + self.cpp + " by = 1){\n");
+ stream.write (" sys::RWlock::ScopedWlock writeLock (accessLock);\n")
+ stream.write (" " + varName + " -= by;\n")
+ if self.style == "wm":
+ stream.write (" if (" + varName + "Low > " + varName + ")\n")
+ stream.write (" " + varName + "Low = " + varName + ";\n")
+ if changeFlag != None:
+ stream.write (" " + changeFlag + " = true;\n")
+ stream.write (" }\n");
+ stream.write (" inline void set_" + varName + " (" + self.cpp + " val){\n");
+ stream.write (" sys::RWlock::ScopedWlock writeLock (accessLock);\n")
+ stream.write (" " + varName + " = val;\n");
+ if self.style == "wm":
+ stream.write (" if (" + varName + "Low > val)\n")
+ stream.write (" " + varName + "Low = val;\n")
+ stream.write (" if (" + varName + "High < val)\n")
+ stream.write (" " + varName + "High = val;\n")
+ if changeFlag != None:
+ stream.write (" " + changeFlag + " = true;\n")
+ stream.write (" }\n");
+
+ def genHiLoStatResets (self, stream, varName):
+ if self.style == "wm":
+ stream.write (" " + varName + "High = " + varName + ";\n")
+ stream.write (" " + varName + "Low = " + varName + ";\n")
+ if self.style == "mma":
+ stream.write (" " + varName + "Count = 0;\n")
+ stream.write (" " + varName + "Total = 0;\n")
+ stream.write (" " + varName + "Min = -1;\n")
+ stream.write (" " + varName + "Max = 0;\n")
+
+ def genWrite (self, stream, varName):
+ if self.style != "mma":
+ stream.write (" " + self.encode.replace ("@", "buf").replace ("#", varName) + ";\n")
+ if self.style == "wm":
+ stream.write (" " + self.encode.replace ("@", "buf") \
+ .replace ("#", varName + "High") + ";\n")
+ stream.write (" " + self.encode.replace ("@", "buf") \
+ .replace ("#", varName + "Low") + ";\n")
+ if self.style == "mma":
+ stream.write (" " + self.encode.replace ("@", "buf") \
+ .replace ("#", varName + "Count") + ";\n")
+ stream.write (" " + self.encode.replace ("@", "buf") \
+ .replace ("#", varName + "Count ? " + varName + "Min : 0") + ";\n")
+ stream.write (" " + self.encode.replace ("@", "buf") \
+ .replace ("#", varName + "Max") + ";\n")
+ stream.write (" " + self.encode.replace ("@", "buf") \
+ .replace ("#", varName + "Count ? " + varName + "Total / " +
+ varName + "Count : 0") + ";\n")
+
+
+ def getReadCode (self, varName, bufName):
+ result = self.decode.replace ("@", bufName).replace ("#", varName)
+ return result
+
+ def getWriteCode (self, varName, bufName):
+ result = self.encode.replace ("@", bufName).replace ("#", varName)
+ return result
+
+#=====================================================================================
+#
+#=====================================================================================
+class TypeSpec:
+ def __init__ (self, file):
+ self.types = {}
+ dom = parse (file)
+ document = dom.documentElement
+ if document.tagName != 'schema-types':
+ raise ValueError ("Expected 'schema-types' in type file")
+
+ for child in document.childNodes:
+ if child.nodeType == Node.ELEMENT_NODE:
+ if child.nodeName == 'type':
+ stype = SchemaType (child)
+ self.types[stype.getName ()] = stype
+ else:
+ raise ValueError ("Unknown type tag '%s'" % child.nodeName)
+
+ def getType (self, name):
+ return self.types[name]
+
+
+#=====================================================================================
+#
+#=====================================================================================
+class Type:
+ def __init__ (self, name, typespec):
+ self.type = typespec.getType (name)
+
+#=====================================================================================
+#
+#=====================================================================================
+class SchemaConfig:
+ def __init__ (self, node, typespec):
+ self.name = None
+ self.type = None
+ self.access = "RO"
+ self.isIndex = 0
+ self.isParentRef = 0
+ self.unit = None
+ self.min = None
+ self.max = None
+ self.maxLen = None
+ self.desc = None
+
+ attrs = node.attributes
+ for idx in range (attrs.length):
+ key = attrs.item(idx).nodeName
+ val = attrs.item(idx).nodeValue
+ if key == 'name':
+ self.name = val
+
+ elif key == 'type':
+ self.type = Type (val, typespec)
+
+ elif key == 'access':
+ self.access = val
+
+ elif key == 'index':
+ if val != 'y':
+ raise ValueError ("Expected 'y' in index attribute")
+ self.isIndex = 1
+
+ elif key == 'parentRef':
+ if val != 'y':
+ raise ValueError ("Expected 'y' in parentRef attribute")
+ self.isParentRef = 1
+
+ elif key == 'unit':
+ self.unit = val
+
+ elif key == 'min':
+ self.min = val
+
+ elif key == 'max':
+ self.max = val
+
+ elif key == 'maxlen':
+ self.maxLen = val
+
+ elif key == 'desc':
+ self.desc = val
+
+ else:
+ raise ValueError ("Unknown attribute in configElement '%s'" % key)
+
+ if self.name == None:
+ raise ValueError ("Missing 'name' attribute in configElement")
+ if self.type == None:
+ raise ValueError ("Missing 'type' attribute in configElement")
+
+ def getName (self):
+ return self.name
+
+ def isConstructorArg (self):
+ if self.access == "RC" and self.isParentRef == 0:
+ return 1
+ return 0
+
+ def genDeclaration (self, stream):
+ stream.write (" " + self.type.type.cpp + " " + self.name + ";\n")
+
+ def genFormalParam (self, stream):
+ stream.write (self.type.type.cpp + " _" + self.name)
+
+ def genAccessor (self, stream):
+ self.type.type.genAccessor (stream, self.name, "configChanged")
+
+ def genSchema (self, stream):
+ stream.write (" ft = FieldTable ();\n")
+ stream.write (" ft.setString (NAME, \"" + self.name + "\");\n")
+ stream.write (" ft.setInt (TYPE, TYPE_" + self.type.type.base +");\n")
+ stream.write (" ft.setInt (ACCESS, ACCESS_" + self.access + ");\n")
+ stream.write (" ft.setInt (INDEX, " + str (self.isIndex) + ");\n")
+ if self.unit != None:
+ stream.write (" ft.setString (UNIT, \"" + self.unit + "\");\n")
+ if self.min != None:
+ stream.write (" ft.setInt (MIN, " + self.min + ");\n")
+ if self.max != None:
+ stream.write (" ft.setInt (MAX, " + self.max + ");\n")
+ if self.maxLen != None:
+ stream.write (" ft.setInt (MAXLEN, " + self.maxLen + ");\n")
+ if self.desc != None:
+ stream.write (" ft.setString (DESC, \"" + self.desc + "\");\n")
+ stream.write (" buf.put (ft);\n\n")
+
+ def genWrite (self, stream):
+ self.type.type.genWrite (stream, self.name)
+
+
+#=====================================================================================
+#
+#=====================================================================================
+class SchemaInst:
+ def __init__ (self, node, typespec):
+ self.name = None
+ self.type = None
+ self.unit = None
+ self.desc = None
+
+ attrs = node.attributes
+ for idx in range (attrs.length):
+ key = attrs.item(idx).nodeName
+ val = attrs.item(idx).nodeValue
+ if key == 'name':
+ self.name = val
+
+ elif key == 'type':
+ self.type = Type (val, typespec)
+
+ elif key == 'unit':
+ self.unit = val
+
+ elif key == 'desc':
+ self.desc = val
+
+ else:
+ raise ValueError ("Unknown attribute in instElement '%s'" % key)
+
+ if self.name == None:
+ raise ValueError ("Missing 'name' attribute in instElement")
+ if self.type == None:
+ raise ValueError ("Missing 'type' attribute in instElement")
+
+ def getName (self):
+ return self.name
+
+ def genDeclaration (self, stream):
+ if self.type.type.style != "mma":
+ stream.write (" " + self.type.type.cpp + " " + self.name + ";\n")
+ if self.type.type.style == 'wm':
+ stream.write (" " + self.type.type.cpp + " " + self.name + "High;\n")
+ stream.write (" " + self.type.type.cpp + " " + self.name + "Low;\n")
+ if self.type.type.style == "mma":
+ stream.write (" " + self.type.type.cpp + " " + self.name + "Count;\n")
+ stream.write (" uint64_t " + self.name + "Total;\n")
+ stream.write (" " + self.type.type.cpp + " " + self.name + "Min;\n")
+ stream.write (" " + self.type.type.cpp + " " + self.name + "Max;\n")
+
+ def genAccessor (self, stream):
+ self.type.type.genAccessor (stream, self.name, "instChanged")
+
+ def genHiLoStatResets (self, stream):
+ self.type.type.genHiLoStatResets (stream, self.name)
+
+ def genSchemaText (self, stream, name, desc):
+ stream.write (" ft = FieldTable ();\n")
+ stream.write (" ft.setString (NAME, \"" + name + "\");\n")
+ stream.write (" ft.setInt (TYPE, TYPE_" + self.type.type.base +");\n")
+ if self.unit != None:
+ stream.write (" ft.setString (UNIT, \"" + self.unit + "\");\n")
+ if desc != None:
+ stream.write (" ft.setString (DESC, \"" + desc + "\");\n")
+ stream.write (" buf.put (ft);\n\n")
+
+ def genSchema (self, stream):
+ if self.type.type.style != "mma":
+ self.genSchemaText (stream, self.name, self.desc)
+ if self.type.type.style == "wm":
+ descHigh = self.desc
+ descLow = self.desc
+ if self.desc != None:
+ descHigh = descHigh + " (High)"
+ descLow = descLow + " (Low)"
+ self.genSchemaText (stream, self.name + "High", descHigh)
+ self.genSchemaText (stream, self.name + "Low", descLow)
+ if self.type.type.style == "mma":
+ descCount = self.desc
+ descMin = self.desc
+ descMax = self.desc
+ descAverage = self.desc
+ if self.desc != None:
+ descCount = descCount + " (Samples)"
+ descMin = descMin + " (Min)"
+ descMax = descMax + " (Max)"
+ descAverage = descAverage + " (Average)"
+ self.genSchemaText (stream, self.name + "Samples", descCount)
+ self.genSchemaText (stream, self.name + "Min", descMin)
+ self.genSchemaText (stream, self.name + "Max", descMax)
+ self.genSchemaText (stream, self.name + "Average", descAverage)
+
+ def genWrite (self, stream):
+ self.type.type.genWrite (stream, self.name)
+
+ def genInitialize (self, stream):
+ val = self.type.type.init
+ if self.type.type.style != "mma":
+ stream.write (" " + self.name + " = " + val + ";\n")
+ if self.type.type.style == "wm":
+ stream.write (" " + self.name + "High = " + val + ";\n")
+ stream.write (" " + self.name + "Low = " + val + ";\n")
+ if self.type.type.style == "mma":
+ stream.write (" " + self.name + "Count = 0;\n")
+ stream.write (" " + self.name + "Min = -1;\n")
+ stream.write (" " + self.name + "Max = 0;\n")
+ stream.write (" " + self.name + "Total = 0;\n")
+
+
+#=====================================================================================
+#
+#=====================================================================================
+class SchemaArg:
+ def __init__ (self, node, typespec):
+ self.name = None
+ self.type = None
+ self.unit = None
+ self.dir = "I"
+ self.min = None
+ self.max = None
+ self.maxLen = None
+ self.desc = None
+ self.default = None
+
+ attrs = node.attributes
+ for idx in range (attrs.length):
+ key = attrs.item(idx).nodeName
+ val = attrs.item(idx).nodeValue
+ if key == 'name':
+ self.name = val
+
+ elif key == 'type':
+ self.type = Type (val, typespec)
+
+ elif key == 'unit':
+ self.unit = val
+
+ elif key == 'dir':
+ self.dir = val.upper ()
+
+ elif key == 'min':
+ self.min = val
+
+ elif key == 'max':
+ self.max = val
+
+ elif key == 'maxlen':
+ self.maxLen = val
+
+ elif key == 'desc':
+ self.desc = val
+
+ elif key == 'default':
+ self.default = val
+
+ else:
+ raise ValueError ("Unknown attribute in arg '%s'" % key)
+
+ if self.name == None:
+ raise ValueError ("Missing 'name' attribute in arg")
+ if self.type == None:
+ raise ValueError ("Missing 'type' attribute in arg")
+
+ def getName (self):
+ return self.name
+
+ def getDir (self):
+ return self.dir
+
+ def genSchema (self, stream):
+ stream.write (" ft = FieldTable ();\n")
+ stream.write (" ft.setString (NAME, \"" + self.name + "\");\n")
+ stream.write (" ft.setInt (TYPE, TYPE_" + self.type.type.base +");\n")
+ stream.write (" ft.setString (DIR, \"" + self.dir + "\");\n")
+ if self.unit != None:
+ stream.write (" ft.setString (UNIT, \"" + self.unit + "\");\n")
+ if self.min != None:
+ stream.write (" ft.setInt (MIN, " + self.min + ");\n")
+ if self.max != None:
+ stream.write (" ft.setInt (MAX, " + self.max + ");\n")
+ if self.maxLen != None:
+ stream.write (" ft.setInt (MAXLEN, " + self.maxLen + ");\n")
+ if self.desc != None:
+ stream.write (" ft.setString (DESC, \"" + self.desc + "\");\n")
+ if self.default != None:
+ stream.write (" ft.setString (DEFAULT, \"" + self.default + "\");\n")
+ stream.write (" buf.put (ft);\n\n")
+
+#=====================================================================================
+#
+#=====================================================================================
+class SchemaMethod:
+ def __init__ (self, parent, node, typespec):
+ self.parent = parent
+ self.name = None
+ self.desc = None
+ self.args = []
+
+ attrs = node.attributes
+ for idx in range (attrs.length):
+ key = attrs.item(idx).nodeName
+ val = attrs.item(idx).nodeValue
+ if key == 'name':
+ self.name = val
+
+ elif key == 'desc':
+ self.desc = val
+
+ else:
+ raise ValueError ("Unknown attribute in method '%s'" % key)
+
+ for child in node.childNodes:
+ if child.nodeType == Node.ELEMENT_NODE:
+ if child.nodeName == 'arg':
+ arg = SchemaArg (child, typespec)
+ self.args.append (arg)
+ else:
+ raise ValueError ("Unknown method tag '%s'" % child.nodeName)
+
+ def getName (self):
+ return self.name
+
+ def getFullName (self):
+ return self.parent.getName().capitalize() + self.name[0:1].upper() +\
+ self.name[1:]
+
+ def getArgCount (self):
+ return len (self.args)
+
+ #===================================================================================
+ # Code Generation Functions. The names of these functions (minus the leading "gen")
+ # match the substitution keywords in the template files.
+ #===================================================================================
+ def genNameUpper (self, stream, variables):
+ stream.write (self.getFullName ().upper ())
+
+ def genNameCamel (self, stream, variables):
+ stream.write (self.getFullName ())
+
+ def genArguments (self, stream, variables):
+ for arg in self.args:
+ ctype = arg.type.type.cpp
+ dirTag = arg.dir.lower() + "_"
+ stream.write (" " + ctype + " " + dirTag + arg.getName () + ";\n")
+
+ def genSchema (self, stream, variables):
+ stream.write (" ft = FieldTable ();\n")
+ stream.write (" ft.setString (NAME, \"" + self.name + "\");\n")
+ stream.write (" ft.setInt (ARGCOUNT, " + str (len (self.args)) + ");\n")
+ if self.desc != None:
+ stream.write (" ft.setString (DESC, \"" + self.desc + "\");\n")
+ stream.write (" buf.put (ft);\n\n")
+ for arg in self.args:
+ arg.genSchema (stream)
+
+#=====================================================================================
+#
+#=====================================================================================
+class SchemaEvent:
+ def __init__ (self, parent, node, typespec):
+ self.parent = parent
+ self.name = None
+ self.desc = None
+ self.args = []
+
+ attrs = node.attributes
+ for idx in range (attrs.length):
+ key = attrs.item(idx).nodeName
+ val = attrs.item(idx).nodeValue
+ if key == 'name':
+ self.name = val
+
+ elif key == 'desc':
+ self.desc = val
+
+ else:
+ raise ValueError ("Unknown attribute in event '%s'" % key)
+
+ for child in node.childNodes:
+ if child.nodeType == Node.ELEMENT_NODE:
+ if child.nodeName == 'arg':
+ arg = SchemaArg (child, typespec)
+ self.args.append (arg)
+ else:
+ raise ValueError ("Unknown event tag '%s'" % child.nodeName)
+
+ def getName (self):
+ return self.name
+
+ def getFullName (self):
+ return self.parent.getName ().capitalize() + self.name.capitalize ()
+
+ def getArgCount (self):
+ return len (self.args)
+
+
+class SchemaClass:
+ def __init__ (self, package, node, typespec, fragments, options):
+ self.packageName = package
+ self.configElements = []
+ self.instElements = []
+ self.methods = []
+ self.events = []
+ self.options = options
+ self.md5Sum = md5.new ()
+
+ self.hash (node)
+
+ attrs = node.attributes
+ self.name = attrs['name'].nodeValue
+
+ children = node.childNodes
+ for child in children:
+ if child.nodeType == Node.ELEMENT_NODE:
+ if child.nodeName == 'configElement':
+ sub = SchemaConfig (child, typespec)
+ self.configElements.append (sub)
+
+ elif child.nodeName == 'instElement':
+ sub = SchemaInst (child, typespec)
+ self.instElements.append (sub)
+
+ elif child.nodeName == 'method':
+ sub = SchemaMethod (self, child, typespec)
+ self.methods.append (sub)
+
+ elif child.nodeName == 'event':
+ sub = SchemaEvent (self, child, typespec)
+ self.events.append (sub)
+
+ elif child.nodeName == 'group':
+ self.expandFragment (child, fragments)
+
+ else:
+ raise ValueError ("Unknown class tag '%s'" % child.nodeName)
+
+ def hash (self, node):
+ attrs = node.attributes
+ self.md5Sum.update (node.nodeName)
+
+ for idx in range (attrs.length):
+ self.md5Sum.update (attrs.item(idx).nodeName)
+ self.md5Sum.update (attrs.item(idx).nodeValue)
+
+ for child in node.childNodes:
+ if child.nodeType == Node.ELEMENT_NODE:
+ self.hash (child)
+
+ def expandFragment (self, node, fragments):
+ attrs = node.attributes
+ name = attrs['name'].nodeValue
+ for fragment in fragments:
+ if fragment.name == name:
+ for config in fragment.configElements:
+ self.configElements.append (config)
+ for inst in fragment.instElements:
+ self.instElements.append (inst)
+ for method in fragment.methods:
+ self.methods.append (method)
+ for event in fragment.events:
+ self.events.append (event)
+ return
+ raise ValueError ("Undefined group '%s'" % name)
+
+ def getName (self):
+ return self.name
+
+ def getMethods (self):
+ return self.methods
+
+ def getEvents (self):
+ return self.events
+
+ #===================================================================================
+ # Code Generation Functions. The names of these functions (minus the leading "gen")
+ # match the substitution keywords in the template files.
+ #===================================================================================
+ def genAccessorMethods (self, stream, variables):
+ for config in self.configElements:
+ if config.access != "RC":
+ config.genAccessor (stream)
+ for inst in self.instElements:
+ inst.genAccessor (stream)
+
+ def genConfigCount (self, stream, variables):
+ stream.write ("%d" % len (self.configElements))
+
+ def genConfigDeclarations (self, stream, variables):
+ for element in self.configElements:
+ element.genDeclaration (stream)
+
+ def genConfigElementSchema (self, stream, variables):
+ for config in self.configElements:
+ config.genSchema (stream)
+
+ def genConstructorArgs (self, stream, variables):
+ # Constructor args are config elements with read-create access
+ result = ""
+ for element in self.configElements:
+ if element.isConstructorArg ():
+ stream.write (", ")
+ element.genFormalParam (stream)
+
+ def genConstructorInits (self, stream, variables):
+ for element in self.configElements:
+ if element.isConstructorArg ():
+ stream.write ("," + element.getName () + "(_" + element.getName () + ")")
+
+ def genDoMethodArgs (self, stream, variables):
+ methodCount = 0
+ inArgCount = 0
+ for method in self.methods:
+ methodCount = methodCount + 1
+ for arg in method.args:
+ if arg.getDir () == "I" or arg.getDir () == "IO":
+ inArgCount = inArgCount + 1
+
+ if methodCount == 0:
+ stream.write ("string, Buffer&, Buffer& outBuf")
+ else:
+ if inArgCount == 0:
+ stream.write ("string methodName, Buffer&, Buffer& outBuf")
+ else:
+ stream.write ("string methodName, Buffer& inBuf, Buffer& outBuf")
+
+ def genEventCount (self, stream, variables):
+ stream.write ("%d" % len (self.events))
+
+ def genEventSchema (self, stream, variables):
+ pass ###########################################################################
+
+ def genHiLoStatResets (self, stream, variables):
+ for inst in self.instElements:
+ inst.genHiLoStatResets (stream)
+
+ def genInitializeElements (self, stream, variables):
+ for inst in self.instElements:
+ inst.genInitialize (stream)
+
+ def genInstChangedStub (self, stream, variables):
+ if len (self.instElements) == 0:
+ stream.write (" // Stub for getInstChanged. There are no inst elements\n")
+ stream.write (" bool getInstChanged (void) { return false; }\n")
+
+ def genInstCount (self, stream, variables):
+ count = 0
+ for inst in self.instElements:
+ count = count + 1
+ if inst.type.type.style == "wm":
+ count = count + 2
+ if inst.type.type.style == "mma":
+ count = count + 3
+ stream.write ("%d" % count)
+
+ def genInstDeclarations (self, stream, variables):
+ for element in self.instElements:
+ element.genDeclaration (stream)
+
+ def genInstElementSchema (self, stream, variables):
+ for inst in self.instElements:
+ inst.genSchema (stream)
+
+ def genMethodArgIncludes (self, stream, variables):
+ for method in self.methods:
+ if method.getArgCount () > 0:
+ stream.write ("#include \"" + (self.options.include_prefix or "") +\
+ "Args" + method.getFullName () + ".h\"\n")
+
+ def genMethodCount (self, stream, variables):
+ stream.write ("%d" % len (self.methods))
+
+ def genMethodHandlers (self, stream, variables):
+ for method in self.methods:
+ stream.write ("\n if (methodName == \"" + method.getName () + "\")\n {\n")
+ if method.getArgCount () == 0:
+ stream.write (" ArgsNone ioArgs;\n")
+ else:
+ stream.write (" Args" + method.getFullName () + " ioArgs;\n")
+ for arg in method.args:
+ if arg.getDir () == "I" or arg.getDir () == "IO":
+ stream.write (" " +\
+ arg.type.type.getReadCode ("ioArgs." +\
+ arg.dir.lower () + "_" +\
+ arg.name, "inBuf") + ";\n")
+
+ stream.write (" status = coreObject->ManagementMethod (METHOD_" +\
+ method.getName().upper() + ", ioArgs);\n")
+ stream.write (" outBuf.putLong (status);\n")
+ stream.write (" outBuf.putShortString (Manageable::StatusText (status));\n")
+ for arg in method.args:
+ if arg.getDir () == "O" or arg.getDir () == "IO":
+ stream.write (" " +\
+ arg.type.type.getWriteCode ("ioArgs." +\
+ arg.dir.lower () + "_" +\
+ arg.name, "outBuf") + ";\n")
+ stream.write (" return;\n }\n")
+
+
+ def genMethodIdDeclarations (self, stream, variables):
+ number = 1
+ for method in self.methods:
+ stream.write (" static const uint32_t METHOD_" + method.getName().upper() +\
+ " = %d;\n" % number)
+ number = number + 1
+
+ def genMethodSchema (self, stream, variables):
+ for method in self.methods:
+ method.genSchema (stream, variables)
+
+ def genNameCap (self, stream, variables):
+ stream.write (self.name.capitalize ())
+
+ def genNameLower (self, stream, variables):
+ stream.write (self.name.lower ())
+
+ def genNamePackageCap (self, stream, variables):
+ stream.write (self.packageName.capitalize ())
+
+ def genNamePackageLower (self, stream, variables):
+ stream.write (self.packageName.lower ())
+
+ def genNameUpper (self, stream, variables):
+ stream.write (self.name.upper ())
+
+ def genParentArg (self, stream, variables):
+ for config in self.configElements:
+ if config.isParentRef == 1:
+ stream.write (", Manageable* _parent")
+ return
+
+ def genParentRefAssignment (self, stream, variables):
+ for config in self.configElements:
+ if config.isParentRef == 1:
+ stream.write (config.getName () + \
+ " = _parent->GetManagementObject ()->getObjectId ();")
+ return
+
+ def genSchemaMD5 (self, stream, variables):
+ sum = self.md5Sum.digest ()
+ for idx in range (len (sum)):
+ if idx != 0:
+ stream.write (",")
+ stream.write (hex (ord (sum[idx])))
+
+ def genWriteConfig (self, stream, variables):
+ for config in self.configElements:
+ config.genWrite (stream);
+
+ def genWriteInst (self, stream, variables):
+ for inst in self.instElements:
+ inst.genWrite (stream);
+
+
+
+class PackageSchema:
+ def __init__ (self, typefile, schemafile, options):
+
+ self.classes = []
+ self.fragments = []
+ self.typespec = TypeSpec (typefile)
+
+ dom = parse (schemafile)
+ document = dom.documentElement
+ if document.tagName != 'schema':
+ raise ValueError ("Expected 'schema' node")
+ attrs = document.attributes
+ self.packageName = attrs['package'].nodeValue
+
+ children = document.childNodes
+ for child in children:
+ if child.nodeType == Node.ELEMENT_NODE:
+ if child.nodeName == 'class':
+ cls = SchemaClass (self.packageName, child, self.typespec,
+ self.fragments, options)
+ self.classes.append (cls)
+
+ elif child.nodeName == 'group':
+ cls = SchemaClass (self.packageName, child, self.typespec,
+ self.fragments, options)
+ self.fragments.append (cls)
+
+ else:
+ raise ValueError ("Unknown schema tag '%s'" % child.nodeName)
+
+ def getPackageName (self):
+ return self.packageName
+
+ def getClasses (self):
+ return self.classes
+
+ def genPackageNameUpper (self, stream, variables):
+ stream.write (self.packageName.upper ())
+
+ def genPackageNameCap (self, stream, variables):
+ stream.write (self.packageName.capitalize ())
+
+ def genClassIncludes (self, stream, variables):
+ for _class in self.classes:
+ stream.write ("#include \"qpid/management/")
+ _class.genNameCap (stream, variables)
+ stream.write (".h\"\n")
+
+ def genClassRegisters (self, stream, variables):
+ for _class in self.classes:
+ stream.write ("agent->RegisterClass (")
+ _class.genNameCap (stream, variables)
+ stream.write ("::packageName, ")
+ _class.genNameCap (stream, variables)
+ stream.write ("::className, ")
+ _class.genNameCap (stream, variables)
+ stream.write ("::md5Sum, ")
+ _class.genNameCap (stream, variables)
+ stream.write ("::writeSchema);\n")
+
diff --git a/qpid/cpp/managementgen/templates/Args.h b/qpid/cpp/managementgen/templates/Args.h
new file mode 100644
index 0000000000..576d891a3f
--- /dev/null
+++ b/qpid/cpp/managementgen/templates/Args.h
@@ -0,0 +1,40 @@
+/*MGEN:commentPrefix=//*/
+#ifndef _ARGS_/*MGEN:Method.NameUpper*/_
+#define _ARGS_/*MGEN:Method.NameUpper*/_
+
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+/*MGEN:Root.Disclaimer*/
+
+#include "qpid/management/Args.h"
+#include <string>
+
+namespace qpid {
+namespace management {
+
+class Args/*MGEN:Method.NameCamel*/ : public Args
+{
+ public:
+/*MGEN:Method.Arguments*/
+};
+
+}}
+
+#endif /*!_ARGS_/*MGEN:Method.NameUpper*/_*/
diff --git a/qpid/cpp/managementgen/templates/Class.cpp b/qpid/cpp/managementgen/templates/Class.cpp
new file mode 100644
index 0000000000..5862685670
--- /dev/null
+++ b/qpid/cpp/managementgen/templates/Class.cpp
@@ -0,0 +1,117 @@
+/*MGEN:commentPrefix=//*/
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+/*MGEN:Root.Disclaimer*/
+
+#include "qpid/log/Statement.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/management/Manageable.h"
+#include "/*MGEN:Class.NameCap*/.h"
+/*MGEN:Class.MethodArgIncludes*/
+
+using namespace qpid::management;
+using namespace qpid::sys;
+using namespace qpid::framing;
+using std::string;
+
+string /*MGEN:Class.NameCap*/::packageName = string ("/*MGEN:Class.NamePackageLower*/");
+string /*MGEN:Class.NameCap*/::className = string ("/*MGEN:Class.NameLower*/");
+uint8_t /*MGEN:Class.NameCap*/::md5Sum[16] =
+ {/*MGEN:Class.SchemaMD5*/};
+
+/*MGEN:Class.NameCap*/::/*MGEN:Class.NameCap*/ (Manageable* _core/*MGEN:Class.ParentArg*//*MGEN:Class.ConstructorArgs*/) :
+ ManagementObject(_core)
+ /*MGEN:Class.ConstructorInits*/
+{
+ /*MGEN:Class.ParentRefAssignment*/
+/*MGEN:Class.InitializeElements*/
+}
+
+/*MGEN:Class.NameCap*/::~/*MGEN:Class.NameCap*/ () {}
+
+namespace {
+ const string NAME("name");
+ const string TYPE("type");
+ const string ACCESS("access");
+ const string INDEX("index");
+ const string UNIT("unit");
+ const string MIN("min");
+ const string MAX("max");
+ const string MAXLEN("maxlen");
+ const string DESC("desc");
+ const string ARGCOUNT("argCount");
+ const string ARGS("args");
+ const string DIR("dir");
+ const string DEFAULT("default");
+}
+
+void /*MGEN:Class.NameCap*/::writeSchema (Buffer& buf)
+{
+ FieldTable ft;
+
+ // Schema class header:
+ buf.putShortString (packageName); // Package Name
+ buf.putShortString (className); // Class Name
+ buf.putBin128 (md5Sum); // Schema Hash
+ buf.putShort (/*MGEN:Class.ConfigCount*/); // Config Element Count
+ buf.putShort (/*MGEN:Class.InstCount*/); // Inst Element Count
+ buf.putShort (/*MGEN:Class.MethodCount*/); // Method Count
+ buf.putShort (/*MGEN:Class.EventCount*/); // Event Count
+
+ // Config Elements
+/*MGEN:Class.ConfigElementSchema*/
+ // Inst Elements
+/*MGEN:Class.InstElementSchema*/
+ // Methods
+/*MGEN:Class.MethodSchema*/
+ // Events
+/*MGEN:Class.EventSchema*/
+}
+
+void /*MGEN:Class.NameCap*/::writeConfig (Buffer& buf)
+{
+ sys::RWlock::ScopedRlock readLock (accessLock);
+ configChanged = false;
+
+ writeTimestamps (buf);
+/*MGEN:Class.WriteConfig*/
+}
+
+void /*MGEN:Class.NameCap*/::writeInstrumentation (Buffer& buf, bool skipHeaders)
+{
+ sys::RWlock::ScopedWlock writeLock (accessLock);
+ instChanged = false;
+
+ if (!skipHeaders)
+ writeTimestamps (buf);
+/*MGEN:Class.WriteInst*/
+
+ // Maintenance of hi-lo statistics
+/*MGEN:Class.HiLoStatResets*/
+}
+
+void /*MGEN:Class.NameCap*/::doMethod (/*MGEN:Class.DoMethodArgs*/)
+{
+ Manageable::status_t status = Manageable::STATUS_UNKNOWN_METHOD;
+/*MGEN:Class.MethodHandlers*/
+ outBuf.putLong (status);
+ outBuf.putShortString (Manageable::StatusText (status));
+}
+
diff --git a/qpid/cpp/managementgen/templates/Class.h b/qpid/cpp/managementgen/templates/Class.h
new file mode 100644
index 0000000000..d95a06479e
--- /dev/null
+++ b/qpid/cpp/managementgen/templates/Class.h
@@ -0,0 +1,76 @@
+/*MGEN:commentPrefix=//*/
+#ifndef _MANAGEMENT_/*MGEN:Class.NameUpper*/_
+#define _MANAGEMENT_/*MGEN:Class.NameUpper*/_
+
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+/*MGEN:Root.Disclaimer*/
+
+#include "qpid/management/ManagementObject.h"
+#include "qpid/framing/Uuid.h"
+
+namespace qpid {
+namespace management {
+
+class /*MGEN:Class.NameCap*/ : public ManagementObject
+{
+ private:
+
+ static std::string packageName;
+ static std::string className;
+ static uint8_t md5Sum[16];
+
+ // Configuration Elements
+/*MGEN:Class.ConfigDeclarations*/
+ // Instrumentation Elements
+/*MGEN:Class.InstDeclarations*/
+ // Private Methods
+ static void writeSchema (qpid::framing::Buffer& buf);
+ void writeConfig (qpid::framing::Buffer& buf);
+ void writeInstrumentation (qpid::framing::Buffer& buf,
+ bool skipHeaders = false);
+ void doMethod (std::string methodName,
+ qpid::framing::Buffer& inBuf,
+ qpid::framing::Buffer& outBuf);
+ writeSchemaCall_t getWriteSchemaCall (void) { return writeSchema; }
+
+/*MGEN:Class.InstChangedStub*/
+ public:
+
+ friend class Package/*MGEN:Class.NamePackageCap*/;
+ typedef boost::shared_ptr</*MGEN:Class.NameCap*/> shared_ptr;
+
+ /*MGEN:Class.NameCap*/ (Manageable* coreObject/*MGEN:Class.ParentArg*//*MGEN:Class.ConstructorArgs*/);
+ ~/*MGEN:Class.NameCap*/ (void);
+
+ std::string getPackageName (void) { return packageName; }
+ std::string getClassName (void) { return className; }
+ uint8_t* getMd5Sum (void) { return md5Sum; }
+
+ // Method IDs
+/*MGEN:Class.MethodIdDeclarations*/
+ // Accessor Methods
+/*MGEN:Class.AccessorMethods*/
+};
+
+}}
+
+
+#endif /*!_MANAGEMENT_/*MGEN:Class.NameUpper*/_*/
diff --git a/qpid/cpp/managementgen/templates/Makefile.mk b/qpid/cpp/managementgen/templates/Makefile.mk
new file mode 100644
index 0000000000..0e6454c13a
--- /dev/null
+++ b/qpid/cpp/managementgen/templates/Makefile.mk
@@ -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.
+#
+/*MGEN:commentPrefix=#*/
+/*MGEN:mgenDir=$(mgen_dir)*/
+/*MGEN:specDir=$(top_srcdir)/../specs*/
+/*MGEN:Root.Disclaimer*/
+
+mgen_generator=/*MGEN:Makefile.GenSources*/
+
+mgen_broker_cpp=/*MGEN:Makefile.GenCppFiles*/
+
+# Header file install rules.
+qpid_managementdir = $(includedir)/qpid/management
+dist_qpid_management_HEADERS = /*MGEN:Makefile.GenHFiles*/
+
+if GENERATE
+$(srcdir)/managementgen.mk: $(mgen_generator)
+ $(mgen_cmd)
+
+$(mgen_generator):
+endif
diff --git a/qpid/cpp/managementgen/templates/Package.cpp b/qpid/cpp/managementgen/templates/Package.cpp
new file mode 100644
index 0000000000..0c5af8d71d
--- /dev/null
+++ b/qpid/cpp/managementgen/templates/Package.cpp
@@ -0,0 +1,32 @@
+/*MGEN:commentPrefix=//*/
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+/*MGEN:Root.Disclaimer*/
+
+#include "qpid/management/Package/*MGEN:Schema.PackageNameCap*/.h"
+/*MGEN:Schema.ClassIncludes*/
+
+using namespace qpid::management;
+
+Package/*MGEN:Schema.PackageNameCap*/::Package/*MGEN:Schema.PackageNameCap*/ (ManagementAgent::shared_ptr agent)
+{
+/*MGEN:Schema.ClassRegisters*/
+}
+
diff --git a/qpid/cpp/managementgen/templates/Package.h b/qpid/cpp/managementgen/templates/Package.h
new file mode 100644
index 0000000000..214f811a1f
--- /dev/null
+++ b/qpid/cpp/managementgen/templates/Package.h
@@ -0,0 +1,41 @@
+/*MGEN:commentPrefix=//*/
+#ifndef _MANAGEMENT_PACKAGE_/*MGEN:Schema.PackageNameUpper*/_
+#define _MANAGEMENT_PACKAGE_/*MGEN:Schema.PackageNameUpper*/_
+
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+/*MGEN:Root.Disclaimer*/
+
+#include "qpid/management/ManagementAgent.h"
+
+namespace qpid {
+namespace management {
+
+class Package/*MGEN:Schema.PackageNameCap*/
+{
+ public:
+ Package/*MGEN:Schema.PackageNameCap*/ (ManagementAgent::shared_ptr agent);
+ ~Package/*MGEN:Schema.PackageNameCap*/ () {}
+};
+
+}}
+
+
+#endif /*!_MANAGEMENT_PACKAGE_/*MGEN:Schema.PackageNameUpper*/_*/
diff --git a/qpid/cpp/qpid-autotools-install b/qpid/cpp/qpid-autotools-install
new file mode 100755
index 0000000000..7fab3d0e9d
--- /dev/null
+++ b/qpid/cpp/qpid-autotools-install
@@ -0,0 +1,205 @@
+#!/bin/sh
+# Written by Jim Meyering
+
+VERSION='2007-07-10 09:09' # UTC
+
+prog_name=`basename $0`
+die () { echo "$prog_name: $*" >&2; exit 1; }
+
+tarballs='
+ http://pkgconfig.freedesktop.org/releases/pkg-config-0.21.tar.gz
+ ftp://ftp.gnu.org/gnu/m4/m4-1.4.10.tar.gz
+ ftp://ftp.gnu.org/gnu/automake/automake-1.10.tar.gz
+ ftp://ftp.gnu.org/gnu/autoconf/autoconf-2.61.tar.gz
+ ftp://ftp.gnu.org/gnu/libtool/libtool-1.5.24.tar.gz
+'
+
+usage() {
+ echo >&2 "\
+Usage: $0 [OPTION]...
+Download, build, and install some tools.
+
+Options:
+ --prefix=PREFIX install tools under specified directory
+ --skip-check do not run "make check" (this can save 50+ min)
+ --help display this help and exit
+
+For example, to install programs into \$HOME/qpid-tools/bin, run this command:
+
+ $prog_name --prefix=\$HOME/qpid-tools
+
+If you've already verified that your system/environment can build working
+versions of these tools, you can make this script complete in just a
+minute or two (rather than about an hour if you let all "make check"
+tests run) by invoking it like this:
+
+ $prog_name --prefix=\$HOME/qpid-tools --skip-check
+
+"
+}
+
+# Get the listed tarballs into the current directory.
+get_sources()
+{
+ case `wget --help` in
+ *'--no-cache'*)
+ WGET_COMMAND='wget -nv --no-cache';;
+ *'--cache=on/off'*)
+ WGET_COMMAND='wget -nv --cache=off';;
+ *'--non-verbose'*)
+ WGET_COMMAND='wget -nv';;
+ *)
+ die 'no wget program found; please install it and try again';;
+ esac
+
+ # Download the each tar-ball along with its signature, if there is one.
+ pkgs=
+ for t in $(echo $tarballs); do
+ base=$(basename $t)
+ pkgs="$pkgs $base"
+ test -f $base || $WGET_COMMAND $t
+
+ # pkg-config has no .sig file.
+ case $base in pkg-config*) continue;; esac
+
+ test -f $base.sig || $WGET_COMMAND $t.sig
+ # Verify each signature.
+ gpg --quiet --verify --trust-model=always \
+ --trusted-key=32419B785D0CDCFC \
+ --trusted-key=3859C03B2E236E47 \
+ --trusted-key=B93F60C6B5C4CE13 \
+ --trusted-key=F382AE19F4850180 \
+ $base.sig > /dev/null 2>&1 \
+ || echo "info: not verifying GPG signature for $base" 1>&2
+ done
+
+ printf 'verifying package SHA1 checksums...' 1>&2
+ sha1sum -c --warn --status <<EOF || die "checksum mismatch"
+69f37c509a4757d747b6f4c091d209ab3984d62f autoconf-2.61.tar.gz
+69dc02b083b9a609b28fc4db129fef6a83ed2339 automake-1.10.tar.gz
+b4c994f1bf4a76d2b0c1d0a6f54d16598c15f3db libtool-1.5.24.tar.gz
+26d47c893722d683308f5d9fc172a11d5b2ad8a9 m4-1.4.10.tar.gz
+b2508ba8404cad46ec42f6f58cbca43ae59d715f pkg-config-0.21.tar.gz
+EOF
+ printf 'ok\n' 1>&2
+ echo $pkgs
+}
+
+#################################################################
+set -e
+
+# Parse options.
+
+make_check=yes
+prefix=
+
+for option
+do
+ case $option in
+ --help) usage; exit;;
+ --skip-check) make_check=no;;
+ --prefix=*) prefix=`expr "$option" : '--prefix=\(.*\)'`;;
+ *) die "$option: unknown option";;
+ esac
+done
+
+test -n "$prefix" \
+ || die "you must specify a --prefix"
+
+case $prefix in
+ /*) ;;
+ *) die 'invalid prefix: '"$prefix"': it must be an absolute name';;
+esac
+
+# Don't run as root.
+# Make sure id -u succeeds.
+my_uid=`id -u`
+test $? = 0 || {
+ echo "$0: cannot run \`id -u'" 1>&2
+ (exit 1); exit 1
+}
+test $my_uid = 0 && die "please don't run this program as root"
+
+# Ensure that prefix is not /usr/bin or /bin, /sbin, etc.
+case $prefix in
+ /bin|/sbin|/usr/bin|/usr/sbin)
+ die "don't set PREFIX to a system directory";;
+ *) ;;
+esac
+
+# Create a build directory, then cd into it for the rest....
+tmpdir=.build-auto-tools
+mkdir -p $tmpdir
+cd $tmpdir
+
+pkgs=$(get_sources)
+
+for pkg in $pkgs; do
+ echo building/installing $pkg...
+ dir=$(basename $pkg .tar.gz)
+ rm -rf dir
+ gzip -dc $pkg|tar xf -
+ cd $dir
+ ./configure CFLAGS=-O2 LDFLAGS=-s --prefix=$prefix > makerr-config 2>&1
+ make -j1 > makerr-build 2>&1
+ if test "$make_check" = yes; then
+ case $pkg in
+ automake*) expected_duration_minutes=40;;
+ autoconf*) expected_duration_minutes=15;;
+ # libtool*) expected_duration_minutes=3;;
+ *);;
+ esac
+ test -n "$expected_duration_minutes" \
+ && echo "running 'make check' for $pkg; NB: this can take over" \
+ "$expected_duration_minutes minutes"
+ case $pkg in
+ # In this package, the check-requires-private test fails.
+ # Change the Makefile so it skips that test.
+ pkg-config-0.21.tar.gz)
+ perl -pi.bak -e 's/check-requires-private //' check/Makefile;;
+
+ esac
+ make -j1 check > makerr-check 2>&1
+ fi
+ make -j1 install > makerr-install 2>&1
+ echo done at $(date +%Y-%m-%d.%T)
+ cd ..
+done
+
+# Without checks (and with existing tarballs), it takes just one minute.
+# Including all checks, it takes nearly an hour on an AMD64/3400+
+
+case $PKG_CONFIG_PATH in
+ $prefix/lib/pkgconfig:/usr/lib/pkgconfig)
+ echo 'Good! your PKG_CONFIG_PATH envvar is already set';;
+ *) cat <<EOF;;
+**************************************************************************
+Be sure that PKG_CONFIG_PATH is set in your environment, e.g.,
+PKG_CONFIG_PATH=$prefix/lib/pkgconfig:/usr/lib/pkgconfig
+**************************************************************************
+EOF
+esac
+
+case $PATH in
+ "$prefix/bin:"*) echo 'Good! your PATH is fine';;
+ *) cat <<EOF;;
+**************************************************************************
+Be sure that "$prefix/bin" is earlier in your PATH than /bin, /usr/bin, etc.
+**************************************************************************
+EOF
+esac
+
+cat <<EOF
+**************************************************************************
+You may want to remove the tool build directory:
+rm -rf $tmpdir
+**************************************************************************
+EOF
+
+## Local Variables:
+## eval: (add-hook 'write-file-hooks 'time-stamp)
+## time-stamp-start: "VERSION='"
+## time-stamp-format: "%:y-%02m-%02d %02H:%02M"
+## time-stamp-time-zone: "UTC"
+## time-stamp-end: "' # UTC"
+## End:
diff --git a/qpid/cpp/qpid-config.in b/qpid/cpp/qpid-config.in
new file mode 100755
index 0000000000..5a65767a8c
--- /dev/null
+++ b/qpid/cpp/qpid-config.in
@@ -0,0 +1,98 @@
+#!/bin/sh
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+exec_prefix_set=no
+includedir=@includedir@
+
+usage()
+{
+ cat <<EOF
+Usage: qpid-config [OPTION] ...
+
+Generic options
+ --version output Qpid version information.
+ --help display this help and exit.
+
+Compilation support options
+ --cflags print pre-processor and compiler flags
+ --libs print library linking information
+
+Install directories Qpid was configured to
+ --prefix[=DIR]
+ --exec-prefix[=DIR]
+
+EOF
+ exit $1
+}
+
+if test $# -eq 0; then
+ usage 1 1>&2
+fi
+
+while test $# -gt 0; do
+ case "$1" in
+ -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) optarg= ;;
+ esac
+
+ case $1 in
+ --prefix=*)
+ prefix=$optarg
+ if test $exec_prefix_set = no ; then
+ exec_prefix=$optarg
+ fi
+ ;;
+ --prefix)
+ echo_prefix=yes
+ ;;
+ --exec-prefix=*)
+ exec_prefix=$optarg
+ exec_prefix_set=yes
+ ;;
+ --exec-prefix)
+ echo_exec_prefix=yes
+ ;;
+ --version)
+ echo @QPID_VERSION@
+ ;;
+ --help)
+ usage 0
+ ;;
+ --cflags)
+ echo_cflags=yes
+ ;;
+ --libs)
+ echo_libs=yes
+ ;;
+ *)
+ usage 1 1>&2
+ ;;
+ esac
+ shift
+done
+
+if test "$echo_prefix" = "yes"; then
+ echo $prefix
+fi
+
+if test "$echo_exec_prefix" = "yes"; then
+ echo $exec_prefix
+fi
+
+if test "$echo_cflags" = "yes"; then
+ if test "$includedir" != "/usr/include" ; then
+ echo -I$includedir
+ fi
+fi
+
+if test "$echo_libs" = "yes"; then
+ if test @libdir@ != /usr/lib ; then
+ my_linker_flags="-L@libdir@"
+ fi
+ echo ${my_linker_flags} -lqpidcommon
+fi
+
+
+
+
diff --git a/qpid/cpp/qpidc.spec.in b/qpid/cpp/qpidc.spec.in
new file mode 100644
index 0000000000..2819f02c45
--- /dev/null
+++ b/qpid/cpp/qpidc.spec.in
@@ -0,0 +1,253 @@
+#
+# Spec file for Qpid C++ packages: qpidc qpidc-devel, qpidd, qpidd-devel
+#
+%define qpidd qpidd
+
+Name: @PACKAGE@
+Version: @VERSION@
+Release: 25%{?dist}
+Summary: Libraries for Qpid C++ client applications
+Group: System Environment/Libraries
+License: Apache Software License
+URL: @URL@
+Source0: @DOWNLOAD_URL@/%{name}-%{version}.tar.gz
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+
+ExclusiveArch: i386 x86_64
+
+BuildRequires: boost-devel
+BuildRequires: cppunit-devel
+BuildRequires: doxygen
+BuildRequires: e2fsprogs-devel
+BuildRequires: graphviz
+BuildRequires: help2man
+BuildRequires: libtool
+BuildRequires: pkgconfig
+BuildRequires: ruby
+
+Requires: boost
+
+Requires(post):/sbin/chkconfig
+Requires(preun):/sbin/chkconfig
+Requires(preun):/sbin/service
+Requires(postun):/sbin/service
+
+%description
+Run-time libraries for AMQP client applications developed using Qpid
+C++. Clients exchange messages with an AMQP message broker using
+the AMQP protocol.
+
+%package devel
+Summary: Header files and documentation for developing Qpid C++ clients
+Group: Development/System
+Requires: %name = %version-%release
+Requires: boost-devel
+Requires: e2fsprogs-devel
+
+%description devel
+Libraries, header files and documentation for developing AMQP clients
+in C++ using Qpid. Qpid implements the AMQP messaging specification.
+
+%package -n %{qpidd}
+Summary: An AMQP message broker daemon
+Group: System Environment/Daemons
+Requires: %name = %version-%release
+Requires: openais
+
+%description -n %{qpidd}
+A message broker daemon that receives stores and routes messages using
+the open AMQP messaging protocol.
+
+%package -n %{qpidd}-devel
+Summary: Libraries and header files for developing Qpid broker extensions
+Group: Development/System
+Requires: %name-devel = %version-%release
+Requires: %{qpidd} = %version-%release
+Requires: openais-devel
+
+%description -n %{qpidd}-devel
+Libraries and header files for developing extensions to the
+Qpid broker daemon.
+
+%pre
+getent group qpidd >/dev/null || groupadd -r qpidd
+getent passwd qpidd >/dev/null || \
+ useradd -r -m -g qpidd -d %{_localstatedir}/lib/qpidd -s /sbin/nologin \
+ -c "Owner of Qpidd Daemons" qpidd
+exit 0
+
+%prep
+%setup -q
+
+%build
+%configure --disable-static --without-cpg CXXFLAGS="-g -O3 -DNDEBUG"
+make %{?_smp_mflags}
+# Remove this generated perl file, we don't need it and it upsets rpmlint.
+rm docs/api/html/installdox
+
+%install
+rm -rf %{buildroot}
+make install-strip DESTDIR=%{buildroot}
+install -Dp -m0755 etc/qpidd %{buildroot}%{_initrddir}/qpidd
+install -d -m0755 %{buildroot}%{_localstatedir}/lib/qpidd
+rm -f %{buildroot}%_libdir/*.a
+rm -f %{buildroot}%_libdir/*.la
+
+%clean
+rm -rf %{buildroot}
+
+%check
+make check
+
+%files
+%defattr(-,root,root,-)
+%doc LICENSE NOTICE README
+%_libdir/libqpidcommon.so.0
+%_libdir/libqpidcommon.so.0.1.0
+%_libdir/libqpidclient.so.0
+%_libdir/libqpidclient.so.0.1.0
+%config(noreplace) %_sysconfdir/qpidd.conf
+
+%files devel
+%defattr(-,root,root,-)
+%_includedir/qpid/*.h
+%_includedir/qpid/amqp_0_10
+%_includedir/qpid/client
+%_includedir/qpid/framing
+%_includedir/qpid/sys
+%_includedir/qpid/log
+%_includedir/qpid/management
+%_libdir/libqpidcommon.so
+%_libdir/libqpidclient.so
+%doc %_datadir/%{name}/examples
+%doc docs/api/html
+
+%files -n %{qpidd}
+%defattr(-,root,root,-)
+%_libdir/libqpidbroker.so.0
+%_libdir/libqpidbroker.so.0.1.0
+%_libdir/libqpidcluster.so.0
+%_libdir/libqpidcluster.so.0.1.0
+%_sbindir/%{qpidd}
+%{_initrddir}/%{qpidd}
+%_localstatedir/lib/qpidd
+%doc %_mandir/man1/%{qpidd}.*
+
+%files -n %{qpidd}-devel
+%defattr(-,root,root,-)
+%doc rpm/README.qpidd-devel
+%defattr(-,root,root,-)
+%_libdir/libqpidbroker.so
+%_libdir/libqpidcluster.so
+%_includedir/qpid/broker
+
+%post -p /sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+%post -n %{qpidd}
+# This adds the proper /etc/rc*.d links for the script
+/sbin/chkconfig --add qpidd
+/sbin/ldconfig
+
+%preun -n %{qpidd}
+# Check that this is actual deinstallation, not just removing for upgrade.
+if [ $1 = 0 ]; then
+ /sbin/service qpidd stop >/dev/null 2>&1 || :
+ /sbin/chkconfig --del qpidd
+fi
+
+%postun -n %{qpidd}
+if [ "$1" -ge "1" ]; then
+ /sbin/service qpidd condrestart >/dev/null 2>&1 || :
+fi
+/sbin/ldconfig
+
+%changelog
+* Mon Mar 31 2008 Nuno Santos <nsantos@redhat.com> - 0.2-25
+- Create user qpidd, start qpidd service as qpidd
+
+* Mon Feb 18 2008 Rafael Schloming <rafaels@redhat.com> - 0.2-24
+- Bug fix for TCK issue in Beta 3
+
+* Thu Feb 14 2008 Rafael Schloming <rafaels@redhat.com> - 0.2-23
+- Bumped to pull in fixes for Beta 3
+
+* Tue Feb 12 2008 Alan Conway <aconway@redhat.com> - 0.2-22
+- Added -g to compile flags for debug symbols.
+
+* Tue Feb 12 2008 Alan Conway <aconway@redhat.com> - 0.2-21
+- Create /var/lib/qpidd correctly.
+
+* Mon Feb 11 2008 Rafael Schloming <rafaels@redhat.com> - 0.2-20
+- bumped for Beta 3
+
+* Mon Jan 21 2008 Gordon Sim <gsim@redhat.com> - 0.2-18
+- bump up rev for recent changes to plugin modules & mgmt
+
+* Thu Jan 03 2008 Nuno Santos <nsantos@redhat.com> - 0.2-17
+- add missing header file SessionManager.h
+
+* Thu Jan 03 2008 Nuno Santos <nsantos@redhat.com> - 0.2-16
+- limit builds to i386 and x86_64 archs
+
+* Thu Jan 03 2008 Nuno Santos <nsantos@redhat.com> - 0.2-15
+- add ruby as a build dependency
+
+* Tue Dec 18 2007 Nuno Santos <nsantos@redhat.com> - 0.2-14
+- include fixes from Gordon Sim (fragmentation, lazy-loading, staging)
+ and Alan Conway (exception handling in the client).
+
+* Thu Dec 6 2007 Alan Conway <aconway@redhat.com> - 0.2-13
+- installcheck target to build examples in installation.
+
+* Thu Nov 8 2007 Alan Conway <aconway@redhat.com> - 0.2-10
+- added examples to RPM package.
+
+* Thu Oct 9 2007 Alan Conway <aconway@redhat.com> - 0.2-9
+- added config(noreplace) for qpidd.conf
+
+* Thu Oct 4 2007 Alan Conway <aconway@redhat.com> - 0.2-8
+- Added qpidd.conf configuration file.
+- Updated man page to detail configuration options.
+
+* Thu Sep 20 2007 Alan Conway <aconway@redhat.com> - 0.2-7
+- Removed apr dependency.
+
+* Wed Aug 1 2007 Alan Conway <aconway@redhat.com> - 0.2-6
+- added --disable-cluster flag
+
+* Tue Apr 17 2007 Alan Conway <aconway@redhat.com> - 0.2-5
+- Add missing Requires: e2fsprogs-devel for qpidc-devel.
+
+* Tue Apr 17 2007 Alan Conway <aconway@redhat.com> - 0.2-4
+- longer broker_start timeout to avoid failures in plague builds.
+
+* Tue Apr 17 2007 Alan Conway <aconway@redhat.com> - 0.2-3
+- Add missing Requires: apr in qpidc.
+
+* Mon Apr 16 2007 Alan Conway <aconway@redhat.com> - 0.2-2
+- Bugfix for memory errors on x86_64.
+
+* Thu Apr 12 2007 Alan Conway <aconway@redhat.com> - 0.2-1
+- Bumped version number for rhm dependencies.
+
+* Wed Apr 11 2007 Alan Conway <aconway@redhat.com> - 0.1-5
+- Add qpidd-devel sub-package.
+
+* Mon Feb 19 2007 Jim Meyering <meyering@redhat.com> - 0.1-4
+- Address http://bugzilla.redhat.com/220630:
+- Remove redundant "cppunit" build-requires.
+- Add --disable-static.
+
+* Thu Jan 25 2007 Alan Conway <aconway@redhat.com> - 0.1-3
+- Applied Jim Meyerings fixes from http://mail-archives.apache.org/mod_mbox/incubator-qpid-dev/200701.mbox/<87hcugzmyp.fsf@rho.meyering.net>
+
+* Mon Dec 22 2006 Alan Conway <aconway@redhat.com> - 0.1-1
+- Fixed all rpmlint complaints (with help from David Lutterkort)
+- Added qpidd --daemon behaviour, fix init.rc scripts
+
+* Fri Dec 8 2006 David Lutterkort <dlutter@redhat.com> - 0.1-1
+- Initial version based on Jim Meyering's sketch and discussions with Alan
+ Conway
+
diff --git a/qpid/cpp/rpm/README.qpidd-devel b/qpid/cpp/rpm/README.qpidd-devel
new file mode 100644
index 0000000000..f64a9de3b3
--- /dev/null
+++ b/qpid/cpp/rpm/README.qpidd-devel
@@ -0,0 +1,7 @@
+
+This package provides header files needed to implement extensions to
+the Qpid broker daemon. This feature is experimental and undocumented,
+it is not require for normal use of qpid.
+
+See http://cwiki.apache.org/qpid/ for more information about the qpid project.
+
diff --git a/qpid/cpp/rubygen/0-10/allsegmenttypes.rb b/qpid/cpp/rubygen/0-10/allsegmenttypes.rb
new file mode 100755
index 0000000000..c4c4095e02
--- /dev/null
+++ b/qpid/cpp/rubygen/0-10/allsegmenttypes.rb
@@ -0,0 +1,34 @@
+#!/usr/bin/env ruby
+$: << ".." # Include .. in load path
+require 'cppgen'
+
+class GenAllSegmentTypes < CppGen
+ def initialize(outdir, amqp)
+ super(outdir, amqp)
+ end
+
+ def generate
+ h_file("tests/allSegmentTypes.h") {
+ include "qpid/amqp_0_10/specification.h"
+ include "qpid/amqp_0_10/Header.h"
+ include "qpid/amqp_0_10/Body.h"
+ genl
+ genl "using namespace qpid::amqp_0_10;"
+ genl
+ scope("template <class Op> size_t allSegmentTypes(Op& op) {"){
+ genl "op(Header());"
+ genl "op(Body());"
+ n = 2;
+ @amqp.classes.each { |c|
+ c.commands.each { |s| genl "op(CommandHolder(#{c.nsname}::#{s.classname}()));" }
+ c.controls.each { |s| genl "op(ControlHolder(#{c.nsname}::#{s.classname}()));" }
+ n += 2
+ }
+ genl "return #{n};"
+ }
+ }
+ end
+end
+
+GenAllSegmentTypes.new($outdir, $amqp).generate();
+
diff --git a/qpid/cpp/rubygen/0-10/exceptions.rb b/qpid/cpp/rubygen/0-10/exceptions.rb
new file mode 100755
index 0000000000..2f62b2ccdf
--- /dev/null
+++ b/qpid/cpp/rubygen/0-10/exceptions.rb
@@ -0,0 +1,55 @@
+#!/usr/bin/env ruby
+$: << ".." # Include .. in load path
+require 'cppgen'
+
+class GenExceptions < CppGen
+
+ def initialize(outdir, amqp)
+ super(outdir, amqp)
+ @ns="qpid::amqp_#{@amqp.version.bars}"
+ @dir="qpid/amqp_#{@amqp.version.bars}"
+ end
+
+ def exceptions_for_enum(enum, base, ns, suffix="")
+ enum.choices.each { |c|
+ name=c.name.typename+suffix+"Exception"
+ genl
+ doxygen_comment { genl c.doc }
+ struct(name, "public #{base}") {
+ genl "#{name}(const std::string& msg=std::string())"
+ genl " : #{base}(#{ns}::#{c.name.shout}, msg) {}"
+ protected
+ genl "std::string getPrefix() const { return \"#{name}\"; }"
+ }
+ }
+ end
+
+ def gen_exceptions()
+ h_file("#{@dir}/exceptions") {
+ include "qpid/amqp_0_10/Exception"
+ namespace("#{@ns}") {
+ error_code = @amqp.class_("execution").domain("error-code").enum
+ exceptions_for_enum(error_code, "SessionAbortedException", "execution")
+ genl
+
+ detach_code = @amqp.class_("session").domain("detach-code").enum
+ exceptions_for_enum(detach_code, "SessionDetachedException", "session", "Detached")
+
+ genl
+ exceptions_for_enum(detach_code, "SessionExpiredException", "session", "Expired")
+ genl
+
+ close_code = @amqp.class_("connection").domain("close-code").enum
+ exceptions_for_enum(close_code, "ConnectionException", "connection")
+ }
+ }
+ end
+
+ def generate()
+ gen_exceptions
+ end
+end
+
+GenExceptions.new($outdir, $amqp).generate();
+
+
diff --git a/qpid/cpp/rubygen/0-10/handlers.rb b/qpid/cpp/rubygen/0-10/handlers.rb
new file mode 100755
index 0000000000..c23eb5faf4
--- /dev/null
+++ b/qpid/cpp/rubygen/0-10/handlers.rb
@@ -0,0 +1,29 @@
+#!/usr/bin/env ruby
+$: << ".." # Include .. in load path
+require 'cppgen'
+
+class GenHandlers < CppGen
+ def initialize(outdir, amqp)
+ super(outdir, amqp)
+ @ns="qpid::amqp_#{@amqp.version.bars}"
+ @dir="qpid/amqp_#{@amqp.version.bars}"
+ end
+
+ def action_handler(type, actions)
+ genl
+ bases=actions.map { |a| "public #{a.fqclassname}::Handler" }
+ struct("#{type}Handler", *bases) { }
+ end
+
+ def generate()
+ h_file("#{@dir}/handlers.h") {
+ include "specification"
+ namespace("#{@ns}") {
+ action_handler "Command", @amqp.collect_all(AmqpCommand)
+ action_handler "Control", @amqp.collect_all(AmqpControl)
+ }
+ }
+ end
+end
+
+GenHandlers.new($outdir, $amqp).generate()
diff --git a/qpid/cpp/rubygen/0-10/specification.rb b/qpid/cpp/rubygen/0-10/specification.rb
new file mode 100755
index 0000000000..7e73d1c91e
--- /dev/null
+++ b/qpid/cpp/rubygen/0-10/specification.rb
@@ -0,0 +1,334 @@
+#!/usr/bin/env ruby
+$: << ".." # Include .. in load path
+require 'cppgen'
+
+class Specification < CppGen
+ def initialize(outdir, amqp)
+ super(outdir, amqp)
+ @ns="qpid::amqp_#{@amqp.version.bars}"
+ @dir="qpid/amqp_#{@amqp.version.bars}"
+ end
+
+ # domains
+
+ def domain_h(d)
+ genl
+ typename=d.name.typename
+ if d.enum
+ scope("enum #{typename} {", "};") {
+ genl d.enum.choices.map { |c|
+ "#{c.name.constname} = #{c.value}" }.join(",\n")
+ }
+ scope("inline SerializeAs<#{typename}, uint8_t> serializable(#{typename}& e) {") {
+ genl "return SerializeAs<#{typename}, uint8_t>(e);"
+ }
+ else
+ genl "typedef #{d.amqp2cpp} #{typename};"
+ end
+ end
+
+ # class constants
+
+ def class_h(c)
+ genl "const uint8_t CODE=#{c.code};"
+ genl "extern const char* NAME;"
+ end
+
+ def class_cpp(c)
+ genl "const char* NAME=\"#{c.fqname}\";"
+ end
+
+ def visitable?(x) x.code and x.size=="4" end
+
+ # Used by structs, commands and controls.
+ def action_struct_h(x, base, consts, &block)
+ genl
+ base = visitable?(x) ? ["public #{base}"] : []
+ struct(x.classname, *base) {
+ x.fields.each { |f| genl "#{f.amqp2cpp} #{f.cppname};" }
+ genl
+ genl "static const char* NAME;"
+ consts.each {
+ |c| genl "static const uint8_t #{c.upcase}=#{(x.send c) or 0};"
+ }
+ genl "static const uint8_t CLASS_CODE=#{x.containing_class.nsname}::CODE;"
+ genl "static const char* CLASS_NAME;"
+ ctor_decl("explicit #{x.classname}", x.parameters(true))
+
+ if visitable? x
+ genl "void accept(Visitor&);"
+ genl "void accept(ConstVisitor&) const;"
+ end
+
+ if (x.fields.empty?)
+ genl "template <class S> void serialize(S&) {}"
+ else
+ scope("template <class S> void serialize(S& s) {") {
+ gen "s"; x.fields.each { |f| gen "(#{f.cppname})"}; genl ";"
+ }
+ end
+ genl
+ yield if block
+ }
+ genl "inline Packer<#{x.classname}> serializable(#{x.classname}& x) { return Packer<#{x.classname}>(x); }" unless x.respond_to? :pack and x.pack == "0"
+ genl "std::ostream& operator << (std::ostream&, const #{x.classname}&);"
+ genl "bool operator==(const #{x.classname}&, const #{x.classname}&);"
+ end
+
+ def action_struct_cpp(x, &block)
+ genl
+ genl "const char* #{x.classname}::NAME=\"#{x.fqname}\";"
+ genl "const char* #{x.classname}::CLASS_NAME=#{x.containing_class.nsname}::NAME;"
+ genl
+ ctor=x.classname+"::"+x.classname
+ ctor_defn(ctor, x.parameters, x.initializers) {}
+
+ if visitable? x
+ genl "void #{x.classname}::accept(Visitor& v) { v.visit(*this); }"
+ genl "void #{x.classname}::accept(ConstVisitor& v) const { v.visit(*this); }"
+ end
+ genl
+ scope("std::ostream& operator << (std::ostream& o, const #{x.classname}&#{"x" unless x.fields.empty?}) {") {
+ genl "o << \"[#{x.fqname}\";";
+ x.fields.each{ |f| genl "o << \" #{f.name}=\" << x.#{f.cppname};" }
+ genl "o << \"]\";"
+ genl "return o;"
+ }
+ yield if block
+ end
+
+ # structs
+
+ def struct_h(s) action_struct_h(s, "Struct", ["size","pack","code"]); end
+ def struct_cpp(s) action_struct_cpp(s) end
+
+ # command and control
+
+ def action_h(a)
+ action_struct_h(a, a.base, ["code"]) {
+ struct("Handler") {
+ scope("void #{a.funcname}(", ");") {
+ genl a.parameters.join(",\n")
+ }
+ }
+ function_defn("template <class T> void invoke", ["T& target"], "const") {
+ genl "target.#{a.funcname}(#{a.values.join(', ')} );"
+ }
+ }
+ end
+
+ def action_cpp(a)
+ action_struct_cpp(a) {
+ scope("void #{a.classname}::Handler::#{a.funcname}(", ")") {
+ genl a.unused_parameters.join(",\n")
+ }
+ scope {
+ genl "assert(0);"
+ genl "throw NotImplementedException(QPID_MSG(\"#{a.fqname} not implemented.\"));"
+ }
+ }
+ end
+
+ # Types that must be generated early because they are used by other types.
+ def pregenerate?(x) not @amqp.used_by[x.fqname].empty?; end
+
+ def pregenerate_class?(c)
+ c.children.select{ |t| (t.is_a? AmqpStruct or t.is_a? AmqpDomain) and pregenerate? t}
+ end
+
+ # Typedefs, enums and forward declarations for classes.
+ def gen_specification_fwd()
+ h_file("#{@dir}/specification_fwd") {
+ include "#{@dir}/built_in_types"
+ namespace(@ns) {
+ # Top level
+ @amqp.domains.each { |d|
+ # segment-type and track are are built in
+ domain_h d unless ["track","segment-type"].include?(d.name)
+ }
+ # Domains/structs that must be generated early because they are used by
+ # other definitions:
+ @amqp.classes.select{ |c| pregenerate_class?(c) }.each { |c|
+ namespace(c.nsname) {
+ c.collect_all(AmqpDomain).each { |d| domain_h d if pregenerate? d }
+ c.collect_all(AmqpStruct).each { |s| genl "class #{s.classname};" if pregenerate? s }
+ }
+ }
+ # Now dependent domains/structs and actions
+ each_class_ns { |c|
+ class_h c
+ c.collect_all(AmqpDomain).each { |d| domain_h d unless pregenerate? d}
+ c.collect_all(AmqpStruct).each { |s| genl "class #{s.classname};" unless pregenerate? s }
+ c.collect_all(AmqpAction).each { |a| genl "class #{a.classname};" unless pregenerate? a }
+ }
+ }
+ }
+ end
+
+ # Generate the specification files
+ def gen_specification()
+ h_file("#{@dir}/specification") {
+ include "#{@dir}/specification_fwd"
+ include "#{@dir}/all_built_in_types"
+ include "#{@dir}/Packer.h"
+ include "<iosfwd>"
+ namespace(@ns) {
+ # Structs that must be generated early because
+ # they are used by other definitions:
+ each_class_ns { |c|
+ c.collect_all(AmqpStruct).each { |s| struct_h s if pregenerate? s }
+ }
+ # Now dependent domains/structs and actions
+ each_class_ns { |c|
+ c.collect_all(AmqpStruct).each { |s| struct_h s unless pregenerate? s}
+ c.collect_all(AmqpAction).each { |a| action_h a }
+ }
+ }
+ }
+
+ cpp_file("#{@dir}/specification") {
+ include "#{@dir}/specification"
+ include "#{@dir}/exceptions"
+ include "<iostream>"
+ ["Command","Control", "Struct"].each { |x| include "#{@dir}/Apply#{x}" }
+ namespace(@ns) {
+ each_class_ns { |c|
+ class_cpp c
+ c.actions.each { |a| action_cpp a}
+ c.collect_all(AmqpStruct).each { |s| struct_cpp(s) }
+ }
+ }
+ }
+ end
+
+ def gen_proxy()
+ h_file("#{@dir}/ProxyTemplate.h") {
+ include "#{@dir}/specification"
+ namespace(@ns) {
+ genl "template <class F, class R=typename F::result_type>"
+ cpp_class("ProxyTemplate") {
+ public
+ genl "ProxyTemplate(F f=F()) : functor(f) {}"
+ @amqp.classes.each { |c|
+ c.actions.each { |a|
+ genl
+ function_defn("R #{a.funcname}", a.parameters) {
+ var=a.name.funcname
+ args = a.arguments.empty? ? "" : "("+a.arguments.join(", ")+")"
+ genl("#{a.fqclassname} #{var}#{args};")
+ genl "return functor(#{var});"
+ }
+ }
+ }
+ private
+ genl "F functor;"
+ }
+ }
+ }
+ end
+
+ def visitor_interface_h(base, subs, is_const)
+ name="#{is_const ? 'Const' : ''}#{base}Visitor"
+ const=is_const ? "const " : ""
+ struct(name) {
+ genl "virtual ~#{name}() {}"
+ genl "typedef #{const}#{base} BaseType;"
+ subs.each{ |s|
+ genl "virtual void visit(#{const}#{s.fqclassname}&) = 0;"
+ }}
+ end
+
+ def visitor_impl(base, subs, is_const)
+ name="#{is_const ? 'Const' : ''}#{base}Visitor"
+ const=is_const ? "const " : ""
+ genl "template <class F>"
+ struct("ApplyVisitor<#{name}, F>", "public ApplyVisitorBase<#{name}, F>") {
+ subs.each{ |s|
+ genl "virtual void visit(#{const}#{s.fqclassname}& x) { this->invoke(x); }"
+ }}
+ end
+
+ def gen_visitor(base, subs)
+ h_file("#{@dir}/#{base}Visitor.h") {
+ include "#{@dir}/specification"
+ namespace("#{@ns}") {
+ visitor_interface_h(base, subs, false)
+ visitor_interface_h(base, subs, true)
+ }}
+
+ h_file("#{@dir}/Apply#{base}.h") {
+ include "#{@dir}/#{base}Visitor.h"
+ include "#{@dir}/apply.h"
+ namespace("#{@ns}") {
+ visitor_impl(base, subs, false)
+ visitor_impl(base, subs, true)
+ }
+ }
+ end
+
+ def gen_holder(base, subs)
+ name=base.caps+"Holder"
+ h_file("#{@dir}/#{name}") {
+ include "#{@dir}/Apply#{base}"
+ include "#{@dir}/Holder"
+ namespace(@ns){
+ namespace("#{base.downcase}_max") {
+ gen "template <class M, class X> "
+ struct("Max") {
+ genl "static const size_t max=(M::max > sizeof(X)) ? M::max : sizeof(X);"
+ }
+ genl "struct Max000 { static const size_t max=0; };"
+ last="Max000"
+ subs.each { |s|
+ genl "typedef Max<#{last}, #{s.fqclassname}> #{last.succ!};"
+ }
+ genl "static const int MAX=#{last}::max;"
+ }
+ holder_base="amqp_0_10::Holder<#{base}Holder, #{base}, #{base.downcase}_max::MAX>"
+ struct("#{name}", "public #{holder_base}") {
+ genl "#{name}() {}"
+ genl "template <class T> explicit #{name}(const T& t) : #{holder_base}(t) {}"
+ genl "using #{holder_base}::operator=;"
+ genl "void set(uint8_t classCode, uint8_t code);"
+ }
+ genl
+ genl "std::ostream& operator<<(std::ostream& o, const #{name}& h);"
+ }
+ }
+
+ cpp_file("#{@dir}/#{name}") {
+ include "#{name}"
+ include "exceptions.h"
+ namespace(@ns) {
+ genl "using framing::in_place;"
+ genl
+ scope("void #{name}::set(uint8_t classCode, uint8_t code) {") {
+ genl "uint16_t key=(classCode<<8)+code;"
+ scope ("switch(key) {") {
+ subs.each { |s|
+ genl "case 0x#{s.full_code.to_s(16)}: *this=in_place<#{s.fqclassname}>(); break;"
+ }
+ genl "default: throw CommandInvalidException(QPID_MSG(\"Invalid class-#{base.downcase} key \" << std::hex << key));"
+ }}
+ genl
+ genl "std::ostream& operator<<(std::ostream& o, const #{name}& h) { return h.get() ? (o << *h.get()) : (o << \"<empty #{name}>\"); }"
+ }
+ }
+ end
+
+ def gen_visitable(base, subs)
+ gen_holder(base, subs)
+ gen_visitor(base, subs)
+ end
+
+ def generate
+ gen_specification_fwd
+ gen_specification
+ gen_proxy
+ gen_visitable("Command", @amqp.collect_all(AmqpCommand))
+ gen_visitable("Control", @amqp.collect_all(AmqpControl))
+ gen_visitable("Struct", @amqp.collect_all(AmqpStruct).select { |s| s.code})
+ end
+end
+
+Specification.new($outdir, $amqp).generate();
diff --git a/qpid/cpp/rubygen/0-10/typecode.rb b/qpid/cpp/rubygen/0-10/typecode.rb
new file mode 100755
index 0000000000..e36b92c07c
--- /dev/null
+++ b/qpid/cpp/rubygen/0-10/typecode.rb
@@ -0,0 +1,99 @@
+#!/usr/bin/env ruby
+$: << ".." # Include .. in load path
+require 'cppgen'
+
+class TypeCode < CppGen
+ def initialize(outdir, amqp)
+ super(outdir, amqp)
+ @ns="qpid::amqp_#{@amqp.version.bars}"
+ @dir="qpid/amqp_#{@amqp.version.bars}"
+ @types = @amqp.collect_all(AmqpType).select { |t| t.code }
+
+ end
+
+ def type_for_code_h()
+ h_file("#{@dir}/TypeForCode") {
+ include "#{@dir}/built_in_types.h"
+ include "#{@dir}/UnknownType.h"
+ namespace(@ns) {
+ genl
+ genl "template <uint8_t Code> struct TypeForCode;"
+ genl
+ @types.each { |t|
+ genl "template <> struct TypeForCode<#{t.code}> { typedef #{t.typename} type; };"
+ }
+ genl
+ genl "template <class V> typename V::result_type"
+ scope("apply_visitor(V& visitor, uint8_t code) {") {
+ scope("switch (code) {", "}") {
+ @types.each { |t|
+ genl "case #{t.code}: return visitor((#{t.typename}*)0);"
+ }
+ genl "default: return visitor((UnknownType*)0);"
+ }
+ }
+ genl
+ genl "std::string typeName(uint8_t code);"
+ }
+ }
+ end
+
+ def type_for_code_cpp()
+ cpp_file("#{@dir}/TypeForCode") {
+ include "<string>"
+ include "<sstream>"
+ namespace(@ns) {
+ namespace("") {
+ struct("Names") {
+ scope("Names() {") {
+ scope("for (int i =0; i < 256; ++i) {") {
+ genl "std::ostringstream os;"
+ genl "os << \"UnknownType<\" << i << \">\";"
+ genl "names[i] = os.str();"
+ }
+ @types.each { |t| genl "names[#{t.code}] = \"#{t.name}\";" }
+ }
+ genl "std::string names[256];"
+ }
+ genl "Names names;"
+ }
+ genl "std::string typeName(uint8_t code) { return names.names[code]; }"
+ }}
+ end
+
+ def code_for_type_h()
+ name="#{@dir}/CodeForType"
+ h_file(name) {
+ include "#{@dir}/built_in_types.h"
+
+ namespace(@ns) {
+ genl
+ genl "template <class T> struct CodeForType;"
+ genl
+ @types.each { |t|
+ genl "template <> struct CodeForType<#{t.typename}> { static const uint8_t value; };"
+ }
+ genl
+ genl "template <class T> uint8_t codeFor(const T&) { return CodeForType<T>::value; }"
+ }
+ }
+
+ cpp_file(name) {
+ include name
+ namespace(@ns) {
+ @types.each { |t|
+ genl "const uint8_t CodeForType<#{t.typename}>::value=#{t.code};"
+ }
+ }
+ }
+ end
+
+ def generate
+ type_for_code_h
+ type_for_code_cpp
+ code_for_type_h
+ end
+end
+
+TypeCode.new($outdir, $amqp).generate();
+
diff --git a/qpid/cpp/rubygen/99-0/MethodBodyConstVisitor.rb b/qpid/cpp/rubygen/99-0/MethodBodyConstVisitor.rb
new file mode 100755
index 0000000000..f9ef95f5a0
--- /dev/null
+++ b/qpid/cpp/rubygen/99-0/MethodBodyConstVisitor.rb
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+$: << ".." # Include .. in load path
+require 'cppgen'
+
+class MethodBodyConstVisitorGen < CppGen
+
+ def initialize(outdir, amqp)
+ super(outdir, amqp)
+ @namespace="qpid::framing"
+ @classname="MethodBodyConstVisitor"
+ @filename="qpid/framing/MethodBodyConstVisitor"
+ end
+
+ def generate()
+ h_file("#{@filename}") {
+ namespace(@namespace) {
+ @amqp.methods_.each { |m| genl "class #{m.body_name};" }
+ cpp_class("MethodBodyConstVisitor") {
+ genl "public:"
+ genl "virtual ~MethodBodyConstVisitor() {}"
+ @amqp.methods_.each { |m| genl "virtual void visit(const #{m.body_name}&) = 0;" }
+ }}}
+ end
+end
+
+MethodBodyConstVisitorGen.new($outdir, $amqp).generate();
+
diff --git a/qpid/cpp/rubygen/99-0/MethodBodyDefaultVisitor.rb b/qpid/cpp/rubygen/99-0/MethodBodyDefaultVisitor.rb
new file mode 100755
index 0000000000..a74b0c06d6
--- /dev/null
+++ b/qpid/cpp/rubygen/99-0/MethodBodyDefaultVisitor.rb
@@ -0,0 +1,35 @@
+#!/usr/bin/env ruby
+$: << ".." # Include .. in load path
+require 'cppgen'
+
+class MethodBodyDefaultVisitorGen < CppGen
+
+ def initialize(outdir, amqp)
+ super(outdir, amqp)
+ @namespace, @classname, @filename = parse_classname("qpid::framing::MethodBodyDefaultVisitor")
+ end
+
+ def generate()
+ h_file(@filename) {
+ include "qpid/framing/MethodBodyConstVisitor"
+ namespace(@namespace) {
+ genl "class AMQMethodBody;"
+ cpp_class(@classname, "public MethodBodyConstVisitor") {
+ genl "public:"
+ genl "virtual void defaultVisit(const AMQMethodBody&) = 0;"
+ @amqp.methods_.each { |m|
+ genl "virtual void visit(const #{m.body_name}&);" }
+ }}}
+
+ cpp_file(@filename) {
+ include(@filename)
+ include("all_method_bodies.h")
+ namespace(@namespace) {
+ @amqp.methods_.each { |m|
+ genl "void #{@classname}::visit(const #{m.body_name}& b) { defaultVisit(b); }"
+ }}}
+ end
+end
+
+MethodBodyDefaultVisitorGen.new($outdir, $amqp).generate();
+
diff --git a/qpid/cpp/rubygen/99-0/MethodHolder.rb b/qpid/cpp/rubygen/99-0/MethodHolder.rb
new file mode 100755
index 0000000000..a708db6676
--- /dev/null
+++ b/qpid/cpp/rubygen/99-0/MethodHolder.rb
@@ -0,0 +1,100 @@
+#!/usr/bin/env ruby
+$: << ".." # Include .. in load path
+require 'cppgen'
+
+class MethodHolderGen < CppGen
+
+ def initialize(outdir, amqp)
+ super(outdir, amqp)
+ @namespace="qpid::framing"
+ @classname="BodyHolder"
+ @filename="qpid/framing/BodyHolder"
+ end
+
+ def gen_max_size()
+ # Generate program to generate MaxSize.h
+ cpp_file("generate_MaxMethodBodySize_h") {
+ include "qpid/framing/AMQHeaderBody"
+ include "qpid/framing/AMQContentBody"
+ include "qpid/framing/AMQHeartbeatBody"
+ @amqp.methods_.each { |m| include "qpid/framing/#{m.body_name}" }
+ genl
+ include "<algorithm>"
+ include "<fstream>"
+ genl
+ genl "using namespace std;"
+ genl "using namespace qpid::framing;"
+ genl
+ scope("int main(int, char** argv) {") {
+ genl "size_t maxSize=0;"
+ genl "maxSize=max(maxSize, sizeof(AMQHeaderBody));"
+ genl "maxSize=max(maxSize, sizeof(AMQContentBody));"
+ genl "maxSize=max(maxSize, sizeof(AMQHeartbeatBody));"
+ @amqp.methods_.each { |m|
+ genl "maxSize=max(maxSize, sizeof(#{m.body_name}));" }
+ gen <<EOS
+ofstream out("qpid/framing/MaxMethodBodySize.h");
+out << "// GENERATED CODE: generated by " << argv[0] << endl;
+out << "namespace qpid{ namespace framing { " << endl;
+out << "const size_t MAX_METHOD_BODY_SIZE=" << maxSize << ";" << endl;
+out << "}}" << endl;
+EOS
+ }
+ }
+ end
+
+ def gen_construct
+ cpp_file(@filename+"_gen") {
+ include @filename
+ include "qpid/framing/AMQHeaderBody"
+ include "qpid/framing/AMQContentBody"
+ include "qpid/framing/AMQHeartbeatBody"
+ @amqp.methods_.each { |m| include "qpid/framing/#{m.body_name}" }
+ include "qpid/framing/FrameDefaultVisitor.h"
+ include "qpid/Exception.h"
+ genl
+ namespace(@namespace) {
+ scope("void #{@classname}::setMethod(ClassId c, MethodId m) {") {
+ scope("switch (c) {") {
+ @amqp.classes.each { |c|
+ scope("case #{c.index}: switch(m) {") {
+ c.methods_.each { |m|
+ genl "case #{m.index}: blob = in_place<#{m.body_name}>(); break;"
+ }
+ genl "default: throw Exception(QPID_MSG(\"Invalid method id \" << int(m) << \" for class #{c.name} \"));"
+ }
+ genl "break;"
+ }
+ genl "default: throw Exception(QPID_MSG(\"Invalid class id \" << int(c)));"
+ }
+ }
+
+ struct("CopyVisitor", "public FrameDefaultVisitor") {
+ genl "using FrameDefaultVisitor::visit;"
+ genl "using FrameDefaultVisitor::defaultVisit;"
+ genl "BodyHolder& holder;"
+ genl "CopyVisitor(BodyHolder& h) : holder(h) {}"
+ ["Header", "Content", "Heartbeat"].each { |type|
+ genl "void visit(const AMQ#{type}Body& x) { holder=x; }"
+ }
+ @amqp.methods_.each { |m|
+ genl "void visit(const #{m.body_name}& x) { holder=x; }"
+ }
+ genl "void defaultVisit(const AMQBody&) { assert(0); }"
+ }
+ genl
+
+ scope("void BodyHolder::setBody(const AMQBody& b) {") {
+ genl "CopyVisitor cv(*this); b.accept(cv);"
+ }
+ }}
+ end
+
+ def generate
+ gen_max_size
+ gen_construct
+ end
+end
+
+MethodHolderGen.new($outdir, $amqp).generate();
+
diff --git a/qpid/cpp/rubygen/99-0/Operations.rb b/qpid/cpp/rubygen/99-0/Operations.rb
new file mode 100755
index 0000000000..c985bb6105
--- /dev/null
+++ b/qpid/cpp/rubygen/99-0/Operations.rb
@@ -0,0 +1,96 @@
+#!/usr/bin/env ruby
+# Usage: output_directory xml_spec_file [xml_spec_file...]
+#
+$: << '..'
+require 'cppgen'
+require 'fileutils'
+require 'etc'
+require 'pathname'
+
+class OperationsGen < CppGen
+
+ def initialize(chassis, outdir, amqp)
+ super(outdir, amqp)
+ @chassis=chassis
+ @classname="AMQP_#{@chassis.caps}Operations"
+ end
+
+ def handler_method (m)
+ return_type = m.result ? m.result.cpptype.ret : "void"
+ gen "\nvirtual #{return_type} #{m.cppname}("
+ gen m.signature.join(",\n")
+ gen ") = 0;\n"
+ end
+
+ def handler_classname(c) c.name.caps+"Handler"; end
+
+ def handler_class(c)
+ if (!c.methods_on(@chassis).empty?)
+ handlerclass=handler_classname c
+ gen <<EOS
+// ==================== class #{handlerclass} ====================
+class #{handlerclass} {
+ // Constructors and destructors
+ public:
+ class Invoker; // Declared in #{@chassis.caps}Invoker
+
+ #{handlerclass}(){};
+ virtual ~#{handlerclass}() {}
+ // Protocol methods
+EOS
+ c.methods_on(@chassis).each { |m| handler_method(m) if !m.content() }
+ gen <<EOS
+}; // class #{handlerclass}
+
+
+EOS
+ end
+ end
+
+ def handler_get(c)
+ if (!c.methods_on(@chassis).empty?)
+ handlerclass=handler_classname c
+ gen "virtual #{handlerclass}* get#{handlerclass}() = 0;\n"
+ end
+ end
+
+ def generate()
+ h_file("qpid/framing/#{@classname}.h") {
+ gen <<EOS
+#include <sstream>
+#include "qpid/framing/ProtocolVersion.h"
+#include "qpid/framing/amqp_structs.h"
+
+namespace qpid {
+namespace framing {
+
+class AMQMethodBody;
+
+class #{@classname} {
+ public:
+ class Invoker; // Declared in #{@chassis.caps}Invoker
+
+ virtual ~#{@classname}() {}
+
+ virtual ProtocolVersion getVersion() const = 0;
+
+ // Inner classes
+EOS
+ indent { @amqp.classes.each { |c| handler_class(c) } }
+ gen <<EOS
+
+ // Method handler get methods
+
+EOS
+ indent { @amqp.classes.each { |c| handler_get(c) } }
+ gen <<EOS
+}; /* class #{@classname} */
+}}
+EOS
+}
+ end
+end
+
+OperationsGen.new("client",ARGV[0], $amqp).generate()
+OperationsGen.new("server",ARGV[0], $amqp).generate()
+
diff --git a/qpid/cpp/rubygen/99-0/OperationsInvoker.rb b/qpid/cpp/rubygen/99-0/OperationsInvoker.rb
new file mode 100755
index 0000000000..642f98ce8e
--- /dev/null
+++ b/qpid/cpp/rubygen/99-0/OperationsInvoker.rb
@@ -0,0 +1,92 @@
+#!/usr/bin/env ruby
+# Usage: output_directory xml_spec_file [xml_spec_file...]
+#
+$: << '..'
+require 'cppgen'
+
+class OperationsInvokerGen < CppGen
+ def initialize(chassis, outdir, amqp)
+ super(outdir, amqp)
+ @chassis=chassis
+ @ops="AMQP_#{@chassis.caps}Operations"
+ @classname="#{@ops}::Invoker"
+ @filename="qpid/framing/#{@chassis.caps}Invoker"
+ end
+
+ def handler(c) "#{@ops}::#{c.cppname}Handler"; end
+ def getter(c) "get#{c.cppname}Handler"; end
+ def invoker(c) "#{handler(c)}::Invoker"; end
+ def visit_methods(c) c.methods_on(@chassis).select { |m| !m.content } end
+
+ def handler_visits_cpp(c)
+ visit_methods(c).each { |m|
+ scope("void #{invoker(c)}::visit(const #{m.body_name}& body) {") {
+ if (m.result)
+ genl "this->encode(body.invoke(target), result.result);"
+ else
+ genl "body.invoke(target);"
+ end
+ genl "result.handled=true;"
+ }
+ }
+ end
+
+ def ops_visits_cpp()
+ @amqp.classes.each { |c|
+ visit_methods(c).each { |m|
+ scope("void #{@classname}::visit(const #{m.body_name}& body) {") {
+ genl "#{handler(c)}::Invoker invoker(*target.#{getter(c)}());"
+ genl "body.accept(invoker);"
+ genl "result=invoker.getResult();"
+ }
+ }
+ }
+ end
+
+ def invoker_h(invoker, target, methods)
+ return if methods.empty?
+ genl
+ cpp_class(invoker, "public qpid::framing::Invoker") {
+ genl "#{target}& target;"
+ public
+ genl("Invoker(#{target}& target_) : target(target_) {}")
+ genl "using MethodBodyDefaultVisitor::visit;"
+ methods.each { |m| genl "void visit(const #{m.body_name}& body);" }
+ }
+ end
+
+ def generate()
+ h_file(@filename) {
+ include "qpid/framing/#{@ops}"
+ include "qpid/framing/Invoker.h"
+ namespace("qpid::framing") {
+ # AMQP_*Operations invoker.
+ methods=@amqp.classes.map { |c| visit_methods(c).to_a }.flatten
+ invoker_h(@classname, @ops, methods)
+
+ # AMQP_*Operations::*Handler invokers.
+ @amqp.classes.each { |c|
+ invoker_h(invoker(c), handler(c), visit_methods(c))
+ }
+ }
+ }
+
+ cpp_file(@filename) {
+ include @filename
+ @amqp.classes.each { |c|
+ visit_methods(c).each { |m|
+ include "qpid/framing/#{m.body_name}"
+ }}
+ namespace("qpid::framing") {
+ ops_visits_cpp
+ @amqp.classes.each { |c|
+ next if visit_methods(c).empty?
+ handler_visits_cpp(c)
+ }
+ }
+ }
+ end
+end
+
+OperationsInvokerGen.new("client",ARGV[0], $amqp).generate()
+OperationsInvokerGen.new("server",ARGV[0], $amqp).generate()
diff --git a/qpid/cpp/rubygen/99-0/Proxy.rb b/qpid/cpp/rubygen/99-0/Proxy.rb
new file mode 100755
index 0000000000..87d809d4ad
--- /dev/null
+++ b/qpid/cpp/rubygen/99-0/Proxy.rb
@@ -0,0 +1,84 @@
+#!/usr/bin/env ruby
+$: << ".." # Include .. in load path
+require 'cppgen'
+
+class ProxyGen < CppGen
+
+ def initialize(chassis, outdir, amqp)
+ super(outdir, amqp)
+ @chassis=chassis
+ @classname="AMQP_#{@chassis.caps}Proxy"
+ @filename="qpid/framing/#{@classname}"
+ end
+
+ def proxy_member(c) c.name.lcaps+"Proxy"; end
+
+ def inner_class_decl(c)
+ cname=c.name.caps
+ cpp_class(cname, "Proxy") {
+ gen <<EOS
+public:
+#{cname}(FrameHandler& f) : Proxy(f) {}
+static #{cname}& get(#{@classname}& proxy) { return proxy.get#{cname}(); }
+EOS
+ c.methods_on(@chassis).each { |m|
+ genl "virtual void #{m.cppname}(#{m.signature.join(",\n ")});"
+ genl
+ }}
+ end
+
+ def inner_class_defn(c)
+ cname=c.cppname
+ c.methods_on(@chassis).each { |m|
+ genl "void #{@classname}::#{cname}::#{m.cppname}(#{m.signature.join(", ")})"
+ scope {
+ params=(["getVersion()"]+m.param_names).join(", ")
+ genl "send(#{m.body_name}(#{params}));"
+ }}
+ end
+
+ def generate
+ # .h file
+ h_file(@filename) {
+ include "qpid/framing/Proxy.h"
+ include "qpid/framing/Array.h"
+ include "qpid/framing/amqp_types.h"
+ include "qpid/framing/amqp_structs.h"
+ namespace("qpid::framing") {
+ cpp_class(@classname, "public Proxy") {
+ public
+ genl "#{@classname}(FrameHandler& out);"
+ genl
+ @amqp.classes.each { |c|
+ inner_class_decl(c)
+ genl
+ genl "#{c.cppname}& get#{c.cppname}() { return #{proxy_member(c)}; }"
+ genl
+ }
+ private
+ @amqp.classes.each{ |c| gen c.cppname+" "+proxy_member(c)+";\n" }
+ }}}
+
+ # .cpp file
+ cpp_file(@filename) {
+ include "<sstream>"
+ include "#{@classname}.h"
+ include "qpid/framing/amqp_types_full.h"
+ @amqp.methods_on(@chassis).each {
+ |m| include "qpid/framing/"+m.body_name
+ }
+ genl
+ namespace("qpid::framing") {
+ genl "#{@classname}::#{@classname}(FrameHandler& f) :"
+ gen " Proxy(f)"
+ @amqp.classes.each { |c| gen ",\n "+proxy_member(c)+"(f)" }
+ genl "{}\n"
+ @amqp.classes.each { |c| inner_class_defn(c) }
+ }}
+ end
+end
+
+
+ProxyGen.new("client", $outdir, $amqp).generate;
+ProxyGen.new("server", $outdir, $amqp).generate;
+
diff --git a/qpid/cpp/rubygen/99-0/Session.rb b/qpid/cpp/rubygen/99-0/Session.rb
new file mode 100644
index 0000000000..1ec78f6167
--- /dev/null
+++ b/qpid/cpp/rubygen/99-0/Session.rb
@@ -0,0 +1,195 @@
+#!/usr/bin/env ruby
+# Usage: output_directory xml_spec_file [xml_spec_file...]
+#
+$: << '..'
+require 'cppgen'
+
+class CppGen
+ def session_methods
+ excludes = ["channel", "connection", "session", "execution"]
+ gen_methods=@amqp.methods_on(@chassis).reject { |m|
+ excludes.include? m.parent.name or m.body_name.include?("010")
+ }
+ end
+
+ def doxygen(m)
+ doxygen_comment {
+ genl m.doc
+ genl
+ m.fields_c.each { |f|
+ genl "@param #{f.cppname}"
+ genl f.doc if f.doc
+ genl
+ }
+ }
+ end
+end
+
+class ContentField # For extra content parameters
+ def cppname() "content" end
+ def signature() "const MethodContent& content" end
+ def sig_default() signature+"="+"DefaultContent(std::string())" end
+ def unpack() "p[arg::content|DefaultContent(std::string())]"; end
+ def doc() "Message content"; end
+end
+
+class AmqpField
+ def unpack() "p[arg::#{cppname}|#{cpptype.default_value}]"; end
+ def sig_default() signature+"="+cpptype.default_value; end
+end
+
+class AmqpMethod
+ def fields_c() content ? fields+[ContentField.new] : fields end
+ def param_names_c() fields_c.map { |f| f.cppname} end
+ def signature_c() fields_c.map { |f| f.signature }; end
+ def sig_c_default() fields_c.map { |f| f.sig_default }; end
+ def argpack_name() "#{parent.cppname}#{name.caps}Parameters"; end
+ def argpack_type()
+ "boost::parameter::parameters<" +
+ fields_c.map { |f| "arg::keyword_tags::"+f.cppname }.join(',') +
+ ">"
+ end
+ def return_type()
+ return "TypedResult<qpid::framing::#{result.cpptype.ret}>" if (result)
+ return "Response" if (not responses().empty?)
+ return "Completion"
+ end
+ def session_function() "#{parent.name.lcaps}#{name.caps}"; end
+end
+
+class SessionNoKeywordGen < CppGen
+
+ def initialize(outdir, amqp)
+ super(outdir, amqp)
+ @chassis="server"
+ @namespace,@classname,@file=
+ parse_classname "qpid::client::no_keyword::Session_#{@amqp.version.bars}"
+ end
+
+ def generate()
+ h_file(@file) {
+ include "qpid/client/SessionBase.h"
+
+ namespace("qpid::client") {
+ genl "using std::string;"
+ genl "using framing::Content;"
+ genl "using framing::FieldTable;"
+ genl "using framing::MethodContent;"
+ genl "using framing::SequenceNumberSet;"
+ genl "using framing::Uuid;"
+ genl
+ namespace("no_keyword") {
+ doxygen_comment {
+ genl "AMQP #{@amqp.version} session API."
+ genl @amqp.class_("session").doc
+ }
+ cpp_class(@classname, "public SessionBase") {
+ public
+ genl "Session_#{@amqp.version.bars}() {}"
+ genl "Session_#{@amqp.version.bars}(shared_ptr<SessionCore> core) : SessionBase(core) {}"
+ session_methods.each { |m|
+ genl
+ doxygen(m)
+ args=m.sig_c_default.join(", ")
+ genl "#{m.return_type} #{m.session_function}(#{args});"
+ }
+ }}}}
+
+ cpp_file(@file) {
+ include @classname
+ include "qpid/framing/all_method_bodies.h"
+ namespace(@namespace) {
+ genl "using namespace framing;"
+ session_methods.each { |m|
+ genl
+ sig=m.signature_c.join(", ")
+ func="#{@classname}::#{m.session_function}"
+ scope("#{m.return_type} #{func}(#{sig}) {") {
+ args=(["ProtocolVersion()"]+m.param_names).join(", ")
+ body="#{m.body_name}(#{args})"
+ sendargs=body
+ sendargs << ", content" if m.content
+ genl "return #{m.return_type}(impl->send(#{sendargs}), impl);"
+ }}}}
+ end
+end
+
+class SessionGen < CppGen
+
+ def initialize(outdir, amqp)
+ super(outdir, amqp)
+ @chassis="server"
+ session="Session_#{@amqp.version.bars}"
+ @base="no_keyword::#{session}"
+ @fqclass=FqClass.new "qpid::client::#{session}"
+ @classname=@fqclass.name
+ @fqbase=FqClass.new("qpid::client::#{@base}")
+ end
+
+ def gen_keyword_decl(m, prefix)
+ return if m.fields_c.empty? # Inherited function will do.
+ scope("BOOST_PARAMETER_MEMFUN(#{m.return_type}, #{m.session_function}, 0, #{m.fields_c.size}, #{m.argpack_name}) {") {
+ scope("return #{prefix}#{m.session_function}(",");") {
+ gen m.fields_c.map { |f| f.unpack() }.join(",\n")
+ }
+ }
+ genl
+ end
+
+ def generate()
+ keyword_methods=session_methods.reject { |m| m.fields_c.empty? }
+ max_arity = keyword_methods.map{ |m| m.fields_c.size }.max
+
+ h_file(@fqclass.file) {
+ include @fqbase.file
+ genl
+ genl "#define BOOST_PARAMETER_MAX_ARITY #{max_arity}"
+ include "<boost/parameter.hpp>"
+ genl
+ namespace("qpid::client") {
+ # Generate keyword tag declarations.
+ namespace("arg") {
+ keyword_methods.map{ |m| m.param_names_c }.flatten.uniq.each { |k|
+ genl "BOOST_PARAMETER_KEYWORD(keyword_tags, #{k})"
+ }}
+ genl
+ # Doxygen comment.
+ doxygen_comment {
+ genl "AMQP #{@amqp.version} session API with keyword arguments."
+ genl <<EOS
+This class provides the same set of functions as #{@base}, but also
+allows parameters be passed using keywords. The keyword is the
+parameter name in the namespace "arg".
+
+For example given the normal function "foo(int x=0, int y=0, int z=0)"
+you could call it in either of the following ways:
+
+@code
+session.foo(1,2,3); // Normal no keywords
+session.foo(arg::z=3, arg::x=1); // Keywords and a default
+@endcode
+
+The keyword functions are easy to use but their declarations are hard
+to read. You may find it easier to read the documentation for #{@base}
+which provides the same set of functions using normal non-keyword
+declarations.
+
+\\ingroup clientapi
+EOS
+ }
+ # Session class.
+ cpp_class(@classname,"public #{@base}") {
+ private
+ genl "#{@classname}(shared_ptr<SessionCore> core) : #{ @base}(core) {}"
+ keyword_methods.each { |m| typedef m.argpack_type, m.argpack_name }
+ genl "friend class Connection;"
+ public
+ genl "#{@classname}() {}"
+ keyword_methods.each { |m| gen_keyword_decl(m,@base+"::") }
+ }}}
+ end
+end
+
+SessionNoKeywordGen.new(ARGV[0], $amqp).generate()
+SessionGen.new(ARGV[0], $amqp).generate()
+
diff --git a/qpid/cpp/rubygen/99-0/all_method_bodies.rb b/qpid/cpp/rubygen/99-0/all_method_bodies.rb
new file mode 100755
index 0000000000..5971d49189
--- /dev/null
+++ b/qpid/cpp/rubygen/99-0/all_method_bodies.rb
@@ -0,0 +1,21 @@
+#!/usr/bin/env ruby
+$: << ".." # Include .. in load path
+require 'cppgen'
+
+class AllMethodBodiesGen < CppGen
+
+ def initialize(outdir, amqp)
+ super(outdir, amqp)
+ @namespace="qpid::framing"
+ @filename="qpid/framing/all_method_bodies"
+ end
+
+ def generate()
+ h_file(@filename) {
+ @amqp.methods_.each { |m| include "qpid/framing/"+m.body_name }
+ }
+ end
+end
+
+AllMethodBodiesGen.new($outdir, $amqp).generate();
+
diff --git a/qpid/cpp/rubygen/99-0/constants.rb b/qpid/cpp/rubygen/99-0/constants.rb
new file mode 100755
index 0000000000..b5f559d504
--- /dev/null
+++ b/qpid/cpp/rubygen/99-0/constants.rb
@@ -0,0 +1,82 @@
+#!/usr/bin/env ruby
+$: << ".." # Include .. in load path
+require 'cppgen'
+
+class ConstantsGen < CppGen
+
+ def initialize(outdir, amqp)
+ super(outdir, amqp)
+ @namespace="qpid::framing"
+ @dir="qpid/framing"
+ end
+
+ def constants_h()
+ h_file("#{@dir}/constants") {
+ namespace(@namespace) {
+ scope("enum AmqpConstant {","};") {
+ l=[]
+ l.concat @amqp.constants.map { |c| "#{c.name.shout}=#{c.value}" }
+ @amqp.classes.each { |c|
+ l << "#{c.name.shout}_CLASS_ID=#{c.index}"
+ l.concat c.methods_.map { |m|
+ "#{c.name.shout}_#{m.name.shout}_METHOD_ID=#{m.index}" }
+ }
+ genl l.join(",\n")
+ }}}
+ end
+
+ def exbase(c)
+ case c.class_
+ when "soft-error" then "ChannelException"
+ when "hard-error" then "ConnectionException"
+ end
+ end
+
+ def reply_exceptions_h()
+ h_file("#{@dir}/reply_exceptions") {
+ include "qpid/Exception"
+ namespace(@namespace) {
+ @amqp.constants.each { |c|
+ base = exbase c
+ if base
+ genl
+ struct(c.name.caps+"Exception", base) {
+ genl "#{c.name.caps}Exception(const std::string& msg=std::string()) : #{base}(#{c.value}, \"#{c.name}: \"+msg) {}"
+ }
+ end
+ }
+ genl
+ genl "void throwReplyException(int code, const std::string& text);"
+ }
+ }
+ end
+
+ def reply_exceptions_cpp()
+ cpp_file("#{@dir}/reply_exceptions") {
+ include "#{@dir}/reply_exceptions"
+ include "<sstream>"
+ namespace("qpid::framing") {
+ scope("void throwReplyException(int code, const std::string& text) {"){
+ scope("switch (code) {") {
+ genl "case 200: break; // No exception"
+ @amqp.constants.each { |c|
+ if exbase c
+ genl "case #{c.value}: throw #{c.name.caps}Exception(text);"
+ end
+ }
+ scope("default:","") {
+ genl "std::ostringstream msg;"
+ genl 'msg << "Invalid reply code " << code << ": " << text;'
+ genl 'throw InvalidArgumentException(msg.str());'
+ }}}}}
+ end
+
+ def generate()
+ constants_h
+ reply_exceptions_h
+ reply_exceptions_cpp
+ end
+end
+
+ConstantsGen.new($outdir, $amqp).generate();
+
diff --git a/qpid/cpp/rubygen/99-0/frame_body_lists.rb b/qpid/cpp/rubygen/99-0/frame_body_lists.rb
new file mode 100644
index 0000000000..b20e4550f3
--- /dev/null
+++ b/qpid/cpp/rubygen/99-0/frame_body_lists.rb
@@ -0,0 +1,31 @@
+$: << ".." # Include .. in load path
+require 'cppgen'
+
+class FrameBodyListsGen < CppGen
+
+ def initialize(outdir, amqp)
+ super(outdir, amqp);
+ end
+
+ def generate
+ h_file("qpid/framing/frame_body_lists.h") {
+ gen <<EOS
+/**@file
+ * Macro lists of frame body classes, used to generate Visitors
+ */
+EOS
+ gen "#define METHOD_BODIES() "
+ @amqp.methods_.each { |m| gen "\\\n (#{m.body_name}) " }
+ gen <<EOS
+
+
+#define OTHER_BODIES() (AMQContentBody)(AMQHeaderBody)(AMQHeartbeatBody))
+
+EOS
+ }
+ end
+end
+
+FrameBodyListsGen.new(ARGV[0], $amqp).generate;
+
+
diff --git a/qpid/cpp/rubygen/99-0/structs.rb b/qpid/cpp/rubygen/99-0/structs.rb
new file mode 100644
index 0000000000..58e175af0f
--- /dev/null
+++ b/qpid/cpp/rubygen/99-0/structs.rb
@@ -0,0 +1,590 @@
+#!/usr/bin/env ruby
+# Usage: output_directory xml_spec_file [xml_spec_file...]
+#
+$: << '..'
+require 'cppgen'
+
+class StructGen < CppGen
+
+ def initialize(outdir, amqp)
+ super(outdir, amqp)
+ end
+
+ EncodingMap={
+ "octet"=>"Octet",
+ "short"=>"Short",
+ "long"=>"Long",
+ "longlong"=>"LongLong",
+ "longstr"=>"LongString",
+ "shortstr"=>"ShortString",
+ "mediumstr"=>"MediumString",
+ "timestamp"=>"LongLong",
+ "table"=>"FieldTable",
+ "content"=>"Content",
+ "long-struct"=>"LongString"
+ }
+ SizeMap={
+ "octet"=>1,
+ "short"=>2,
+ "long"=>4,
+ "longlong"=>8,
+ "timestamp"=>8
+ }
+
+ ValueTypes=["octet", "short", "long", "longlong", "timestamp"]
+
+ def is_packed(s)
+ #return true
+ s.kind_of?(AmqpStruct) or s.body_name.include?("010")
+ end
+
+ def execution_header?(s)
+ #false and s.kind_of? AmqpMethod and s.parent.l4?
+ s.kind_of? AmqpMethod and s.parent.name.include?("010") and not s.parent.control?
+ end
+
+ def has_bitfields_only(s)
+ s.fields.select {|f| f.domain.type_ != "bit"}.empty?
+ end
+
+ def default_initialisation(s)
+ params = s.fields.select {|f| ValueTypes.include?(f.domain.type_) || (!is_packed(s) && f.domain.type_ == "bit")}
+ strings = params.collect {|f| "#{f.cppname}(0)"}
+ strings << "flags(0)" if (is_packed(s))
+ if strings.empty?
+ return ""
+ else
+ return " : " + strings.join(", ")
+ end
+ end
+
+ def printable_form(f)
+ if (f.cpptype.name == "uint8_t")
+ return "(int) " + f.cppname
+ elsif (f.domain.type_ == "bit")
+ return "get#{f.name.caps}()"
+ else
+ return f.cppname
+ end
+ end
+
+ def flag_mask(s, i)
+ pos = SizeMap[s.pack]*8 - 8 - (i/8)*8 + (i % 8)
+ return "(1 << #{pos})"
+ end
+
+ def encode_packed_struct(s)
+ genl s.cpp_pack_type.encode('flags', 'buffer')
+ process_packed_fields(s) { |f, i| encode_packed_field(s, f, i) unless f.domain.type_ == "bit" }
+ end
+
+ def decode_packed_struct(s)
+ genl "#{s.cpp_pack_type.decode('flags', 'buffer')}"
+ process_packed_fields(s) { |f, i| decode_packed_field(s, f, i) unless f.domain.type_ == "bit" }
+ end
+
+ def size_packed_struct(s)
+ genl "total += #{SizeMap[s.pack]};"
+ process_packed_fields(s) { |f, i| size_packed_field(s, f, i) unless f.domain.type_ == "bit" }
+ end
+
+ def print_packed_struct(s)
+ process_packed_fields(s) { |f, i| print_packed_field(s, f, i) }
+ end
+
+ def encode_packed_field(s, f, i)
+ genl "if (flags & #{flag_mask(s, i)})"
+ indent { genl f.domain.cpptype.encode(f.cppname,"buffer") }
+ end
+
+ def decode_packed_field(s, f, i)
+ genl "if (flags & #{flag_mask(s, i)})"
+ indent { genl f.domain.cpptype.decode(f.cppname,"buffer") }
+ end
+
+ def size_packed_field(s, f, i)
+ genl "if (flags & #{flag_mask(s, i)})"
+ indent { generate_size(f, []) }
+ end
+
+ def print_packed_field(s, f, i)
+ genl "if (flags & #{flag_mask(s, i)})"
+ indent {
+ genl "out << \"#{f.name}=\" << #{printable_form(f)} << \"; \";"
+ }
+ end
+
+ def generate_encode(f, combined)
+ if (f.domain.type_ == "bit")
+ genl "uint8_t #{f.cppname}_bits = #{f.cppname};"
+ count = 0
+ combined.each { |c| genl "#{f.cppname}_bits |= #{c.cppname} << #{count += 1};" }
+ genl "buffer.putOctet(#{f.cppname}_bits);"
+ else
+ genl f.domain.cpptype.encode(f.cppname,"buffer")
+ end
+ end
+
+ def generate_decode(f, combined)
+ if (f.domain.type_ == "bit")
+ genl "uint8_t #{f.cppname}_bits = buffer.getOctet();"
+ genl "#{f.cppname} = 1 & #{f.cppname}_bits;"
+ count = 0
+ combined.each { |c| genl "#{c.cppname} = (1 << #{count += 1}) & #{f.cppname}_bits;" }
+ else
+ genl f.domain.cpptype.decode(f.cppname,"buffer")
+ end
+ end
+
+ def generate_size(f, combined)
+ if (f.domain.type_ == "bit")
+ names = ([f] + combined).collect {|g| g.cppname}
+ genl "total += 1;//#{names.join(", ")}"
+ else
+ size = SizeMap[f.domain.type_]
+ if (size)
+ genl "total += #{size};//#{f.cppname}"
+ elsif (f.cpptype.name == "SequenceNumberSet")
+ genl "total += #{f.cppname}.encodedSize();"
+ else
+ encoded = EncodingMap[f.domain.type_]
+ gen "total += ("
+ gen "4 + " if encoded == "LongString"
+ gen "2 + " if encoded == "MediumString"
+ gen "1 + " if encoded == "ShortString"
+ genl "#{f.cppname}.size());"
+ end
+ end
+ end
+
+ def process_packed_fields(s)
+ s.fields.each { |f| yield f, s.fields.index(f) }
+ end
+
+ def process_fields(s)
+ last = nil
+ count = 0
+ bits = []
+ s.fields.each {
+ |f| if (last and last.bit? and f.bit? and count < 7)
+ count += 1
+ bits << f
+ else
+ if (last and last.bit?)
+ yield last, bits
+ count = 0
+ bits = []
+ end
+ if (not f.bit?)
+ yield f
+ end
+ last = f
+ end
+ }
+ if (last and last.bit?)
+ yield last, bits
+ end
+ end
+
+ def all_fields_via_accessors(s)
+ s.fields.collect { |f| "get#{f.name.caps}()" }.join(", ")
+ end
+
+ def methodbody_extra_defs(s)
+ if (s.parent.control?)
+ genl "virtual uint8_t type() const { return 0;/*control segment*/ }"
+ end
+
+
+ gen <<EOS
+ typedef #{s.result ? s.result.struct.cpptype.name : 'void'} ResultType;
+
+ template <class T> ResultType invoke(T& invocable) const {
+ return invocable.#{s.cppname}(#{all_fields_via_accessors(s)});
+ }
+
+ using AMQMethodBody::accept;
+ void accept(MethodBodyConstVisitor& v) const { v.visit(*this); }
+
+ ClassId amqpClassId() const { return CLASS_ID; }
+ MethodId amqpMethodId() const { return METHOD_ID; }
+ bool isContentBearing() const { return #{s.content ? "true" : "false" }; }
+ bool resultExpected() const { return #{s.result ? "true" : "false"}; }
+ bool responseExpected() const { return #{s.responses().empty? ? "false" : "true"}; }
+EOS
+ end
+
+ def define_constructor(name, s)
+ if (s.fields.size > 0)
+ genl "#{name}("
+ if (s.kind_of? AmqpMethod)
+ indent {gen "ProtocolVersion, "}
+ end
+ indent { gen s.fields.collect { |f| "#{f.cpptype.param} _#{f.cppname}" }.join(",\n") }
+ genl ") : "
+ if (is_packed(s))
+ initialisers = s.fields.select { |f| f.domain.type_ != "bit"}.collect { |f| "#{f.cppname}(_#{f.cppname})"}
+
+ initialisers << "flags(0)"
+ indent { gen initialisers.join(",\n") }
+ genl "{"
+ indent {
+ process_packed_fields(s) { |f, i| genl "set#{f.name.caps}(_#{f.cppname});" if f.domain.type_ == "bit"}
+ process_packed_fields(s) { |f, i| genl "flags |= #{flag_mask(s, i)};" unless f.domain.type_ == "bit"}
+ }
+ genl "}"
+ else
+ indent { gen s.fields.collect { |f| " #{f.cppname}(_#{f.cppname})" }.join(",\n") }
+ genl "{}"
+ end
+ end
+ #default constructors:
+ if (s.kind_of? AmqpMethod)
+ genl "#{name}(ProtocolVersion=ProtocolVersion()) #{default_initialisation(s)} {}"
+ end
+ if (s.kind_of? AmqpStruct)
+ genl "#{name}() #{default_initialisation(s)} {}"
+ end
+ end
+
+ def define_packed_field_accessors(s, f, i)
+ if (s.kind_of? AmqpMethod)
+ define_packed_field_accessors_for_method(s, f, i)
+ else
+ define_packed_field_accessors_for_struct(s, f, i)
+ end
+ end
+
+ def define_packed_field_accessors_for_struct(s, f, i)
+ if (f.domain.type_ == "bit")
+ genl "void #{s.cppname}::set#{f.name.caps}(#{f.cpptype.param} _#{f.cppname}) {"
+ indent {
+ genl "if (_#{f.cppname}) flags |= #{flag_mask(s, i)};"
+ genl "else flags &= ~#{flag_mask(s, i)};"
+ }
+ genl "}"
+ genl "#{f.cpptype.ret} #{s.cppname}::get#{f.name.caps}() const { return flags & #{flag_mask(s, i)}; }"
+ else
+ genl "void #{s.cppname}::set#{f.name.caps}(#{f.cpptype.param} _#{f.cppname}) {"
+ indent {
+ genl "#{f.cppname} = _#{f.cppname};"
+ genl "flags |= #{flag_mask(s, i)};"
+ }
+ genl "}"
+ genl "#{f.cpptype.ret} #{s.cppname}::get#{f.name.caps}() const { return #{f.cppname}; }"
+ if (f.cpptype.name == "FieldTable")
+ genl "#{f.cpptype.name}& #{s.cppname}::get#{f.name.caps}() {"
+ indent {
+ genl "flags |= #{flag_mask(s, i)};"#treat the field table as having been 'set'
+ genl "return #{f.cppname};"
+ }
+ genl "}"
+ end
+ genl "bool #{s.cppname}::has#{f.name.caps}() const { return flags & #{flag_mask(s, i)}; }"
+ genl "void #{s.cppname}::clear#{f.name.caps}Flag() { flags &= ~#{flag_mask(s, i)}; }"
+ end
+ genl ""
+ end
+
+ def define_packed_field_accessors_for_method(s, f, i)
+ if (f.domain.type_ == "bit")
+ genl "void #{s.body_name}::set#{f.name.caps}(#{f.cpptype.param} _#{f.cppname}) {"
+ indent {
+ genl "if (_#{f.cppname}) flags |= #{flag_mask(s, i)};"
+ genl "else flags &= ~#{flag_mask(s, i)};"
+ }
+ genl "}"
+ genl "#{f.cpptype.ret} #{s.body_name}::get#{f.name.caps}() const { return flags & #{flag_mask(s, i)}; }"
+ else
+ genl "void #{s.body_name}::set#{f.name.caps}(#{f.cpptype.param} _#{f.cppname}) {"
+ indent {
+ genl "#{f.cppname} = _#{f.cppname};"
+ genl "flags |= #{flag_mask(s, i)};"
+ }
+ genl "}"
+ genl "#{f.cpptype.ret} #{s.body_name}::get#{f.name.caps}() const { return #{f.cppname}; }"
+ if (f.cpptype.name == "FieldTable")
+ genl "#{f.cpptype.name}& #{s.body_name}::get#{f.name.caps}() {"
+ indent {
+ genl "flags |= #{flag_mask(s, i)};"#treat the field table as having been 'set'
+ genl "return #{f.cppname};"
+ }
+ genl "}"
+ end
+ genl "bool #{s.body_name}::has#{f.name.caps}() const { return flags & #{flag_mask(s, i)}; }"
+ genl "void #{s.body_name}::clear#{f.name.caps}Flag() { flags &= ~#{flag_mask(s, i)}; }"
+ end
+ genl ""
+ end
+
+ def define_packed_accessors(s)
+ process_packed_fields(s) { |f, i| define_packed_field_accessors(s, f, i) }
+ end
+
+ def declare_packed_accessors(f)
+ genl "void set#{f.name.caps}(#{f.cpptype.param} _#{f.cppname});";
+ genl "#{f.cpptype.ret} get#{f.name.caps}() const;"
+ if (f.cpptype.name == "FieldTable")
+ genl "#{f.cpptype.name}& get#{f.name.caps}();"
+ end
+ if (f.domain.type_ != "bit")
+ #extra 'accessors' for packed fields:
+ genl "bool has#{f.name.caps}() const;"
+ genl "void clear#{f.name.caps}Flag();"
+ end
+ end
+
+ def define_accessors(f)
+ genl "void set#{f.name.caps}(#{f.cpptype.param} _#{f.cppname}) { #{f.cppname} = _#{f.cppname}; }"
+ genl "#{f.cpptype.ret} get#{f.name.caps}() const { return #{f.cppname}; }"
+ if (f.cpptype.name == "FieldTable")
+ genl "#{f.cpptype.name}& get#{f.name.caps}() { return #{f.cppname}; }"
+ end
+ end
+
+ def define_struct(s)
+ classname = s.cppname
+ inheritance = ""
+ if (s.kind_of? AmqpMethod)
+ classname = s.body_name
+ if (execution_header?(s))
+ inheritance = ": public ModelMethod"
+ else
+ inheritance = ": public AMQMethodBody"
+ end
+ end
+
+ h_file("qpid/framing/#{classname}.h") {
+ if (s.kind_of? AmqpMethod)
+ gen <<EOS
+#include "qpid/framing/AMQMethodBody.h"
+#include "qpid/framing/AMQP_ServerOperations.h"
+#include "qpid/framing/MethodBodyConstVisitor.h"
+EOS
+ end
+ include "qpid/framing/ModelMethod.h" if (execution_header?(s))
+
+ #need to include any nested struct definitions
+ s.fields.each { |f| include f.cpptype.name if f.domain.struct }
+
+ gen <<EOS
+
+#include <ostream>
+#include "qpid/framing/amqp_types_full.h"
+
+namespace qpid {
+namespace framing {
+
+class #{classname} #{inheritance} {
+EOS
+ if (is_packed(s))
+ indent { s.fields.each { |f| genl "#{f.cpptype.name} #{f.cppname};" unless f.domain.type_ == "bit"} }
+ indent {
+ genl "#{s.cpp_pack_type.name} flags;"
+ }
+ else
+ indent { s.fields.each { |f| genl "#{f.cpptype.name} #{f.cppname};" } }
+ end
+ genl "public:"
+ if (s.kind_of? AmqpMethod)
+ indent { genl "static const ClassId CLASS_ID = #{s.parent.index};" }
+ indent { genl "static const MethodId METHOD_ID = #{s.index};" }
+ end
+
+ if (s.kind_of? AmqpStruct)
+ if (s.type_)
+ if (s.result?)
+ #as result structs have types that are only unique to the
+ #class, they have a class dependent qualifier added to them
+ #(this is inline with current python code but a formal
+ #solution is expected from the WG)
+ indent { genl "static const uint16_t TYPE = #{s.type_} + #{s.parent.parent.parent.index} * 256;" }
+ else
+ indent { genl "static const uint16_t TYPE = #{s.type_};" }
+ end
+ end
+ end
+
+ indent {
+ define_constructor(classname, s)
+ genl ""
+ if (is_packed(s))
+ s.fields.each { |f| declare_packed_accessors(f) }
+ else
+ s.fields.each { |f| define_accessors(f) }
+ end
+ }
+ if (s.kind_of? AmqpMethod)
+ methodbody_extra_defs(s)
+ end
+ if (s.kind_of? AmqpStruct)
+ indent {genl "friend std::ostream& operator<<(std::ostream&, const #{classname}&);" }
+ end
+
+ gen <<EOS
+ void encode(Buffer&) const;
+ void decode(Buffer&, uint32_t=0);
+ void encodeStructBody(Buffer&) const;
+ void decodeStructBody(Buffer&, uint32_t=0);
+ uint32_t size() const;
+ uint32_t bodySize() const;
+ void print(std::ostream& out) const;
+}; /* class #{classname} */
+
+}}
+EOS
+ }
+ cpp_file("qpid/framing/#{classname}.cpp") {
+ if (is_packed(s) || s.fields.size > 0 || execution_header?(s))
+ buffer = "buffer"
+ else
+ buffer = "/*buffer*/"
+ end
+ gen <<EOS
+#include "#{classname}.h"
+
+using namespace qpid::framing;
+
+EOS
+
+ if (is_packed(s))
+ define_packed_accessors(s)
+ end
+ gen <<EOS
+void #{classname}::encodeStructBody(Buffer& #{buffer}) const
+{
+EOS
+ if (execution_header?(s))
+ genl "encodeHeader(buffer);"
+ end
+
+ if (is_packed(s))
+ indent {encode_packed_struct(s)}
+ else
+ indent { process_fields(s) { |f, combined| generate_encode(f, combined) } }
+ end
+ gen <<EOS
+}
+
+void #{classname}::encode(Buffer& buffer) const
+{
+EOS
+ indent {
+ if (s.kind_of? AmqpStruct)
+ if (s.type_)
+ genl "buffer.put#{s.size.caps}(bodySize() + 2/*typecode*/);" if s.size
+ genl "buffer.putShort(TYPE);"
+ else
+ genl "buffer.put#{s.size.caps}(bodySize());" if s.size
+ end
+ end
+ genl "encodeStructBody(buffer);"
+ }
+ gen <<EOS
+}
+
+void #{classname}::decodeStructBody(Buffer& #{buffer}, uint32_t /*size*/)
+{
+EOS
+ if (execution_header?(s))
+ genl "decodeHeader(buffer);"
+ end
+
+ if (is_packed(s))
+ indent {decode_packed_struct(s)}
+ else
+ indent { process_fields(s) { |f, combined| generate_decode(f, combined) } }
+ end
+ gen <<EOS
+}
+
+void #{classname}::decode(Buffer& buffer, uint32_t /*size*/)
+{
+EOS
+ indent {
+ if (s.kind_of? AmqpStruct)
+ genl "buffer.get#{s.size.caps}();" if s.size
+ genl "if (TYPE != buffer.getShort()) throw InternalErrorException(\"Bad type code for struct\");" if s.type_
+ end
+ genl "decodeStructBody(buffer);"
+ }
+ gen <<EOS
+}
+
+uint32_t #{classname}::bodySize() const
+{
+ uint32_t total = 0;
+EOS
+ if (execution_header?(s))
+ genl "total += headerSize();"
+ end
+
+ if (is_packed(s))
+ indent {size_packed_struct(s)}
+ else
+ indent { process_fields(s) { |f, combined| generate_size(f, combined) } }
+ end
+ gen <<EOS
+ return total;
+}
+
+uint32_t #{classname}::size() const
+{
+ uint32_t total = bodySize();
+EOS
+ if (s.kind_of? AmqpStruct)
+ genl "total += #{SizeMap[s.size]}/*size field*/;" if s.size
+ genl "total += 2/*typecode*/;" if s.type_
+ end
+ gen <<EOS
+ return total;
+}
+
+void #{classname}::print(std::ostream& out) const
+{
+ out << "{#{classname}: ";
+EOS
+ if (is_packed(s))
+ indent {print_packed_struct(s)}
+ else
+ copy = Array.new(s.fields)
+ f = copy.shift
+
+ indent {
+ genl "out << \"#{f.name}=\" << #{printable_form(f)};" if f
+ copy.each { |f| genl "out << \"; #{f.name}=\" << #{printable_form(f)};" }
+ }
+ end
+ gen <<EOS
+ out << "}";
+}
+EOS
+
+ if (s.kind_of? AmqpStruct)
+ gen <<EOS
+namespace qpid{
+namespace framing{
+
+ std::ostream& operator<<(std::ostream& out, const #{classname}& s)
+ {
+ s.print(out);
+ return out;
+ }
+
+}
+}
+EOS
+ end
+}
+ end
+
+ def generate()
+ @amqp.structs.each { |s| define_struct(s) }
+ @amqp.methods_.each { |m| define_struct(m) }
+ #generate a single include file containing the list of structs for convenience
+ h_file("qpid/framing/amqp_structs.h") { @amqp.structs.each { |s| genl "#include \"#{s.cppname}.h\"" } }
+ end
+end
+
+StructGen.new(ARGV[0], $amqp).generate()
+
diff --git a/qpid/cpp/rubygen/MethodBodyDefaultVisitor.rb b/qpid/cpp/rubygen/MethodBodyDefaultVisitor.rb
new file mode 100755
index 0000000000..1fff1d51db
--- /dev/null
+++ b/qpid/cpp/rubygen/MethodBodyDefaultVisitor.rb
@@ -0,0 +1,34 @@
+#!/usr/bin/env ruby
+$: << ".." # Include .. in load path
+require 'cppgen'
+
+class MethodBodyDefaultVisitorGen < CppGen
+
+ def initialize(outdir, amqp)
+ super(outdir, amqp)
+ set_classname("qpid::framing::MethodBodyDefaultVisitor")
+ end
+
+ def generate()
+ h_file(@filename) {
+ include "qpid/framing/MethodBodyConstVisitor"
+ namespace(@namespace) {
+ genl
+ cpp_class(@classname, "public MethodBodyConstVisitor") {
+ genl "public:"
+ genl "virtual void defaultVisit() = 0;"
+ @amqp.methods_.each { |m|
+ genl "virtual void visit(const #{m.body_name}&);" }
+ }}}
+
+ cpp_file(@filename) {
+ include(@filename)
+ namespace(@namespace) {
+ @amqp.methods_.each { |m|
+ genl "void #{@classname}::visit(const #{m.body_name}&) { defaultVisit(); }"
+ }}}
+ end
+end
+
+MethodBodyDefaultVisitorGen.new($outdir, $amqp).generate();
+
diff --git a/qpid/cpp/rubygen/README b/qpid/cpp/rubygen/README
new file mode 100644
index 0000000000..a1fd6cfec8
--- /dev/null
+++ b/qpid/cpp/rubygen/README
@@ -0,0 +1,17 @@
+RUBY CODE GENERATOR
+
+Run ./generate for usage.
+Examples in samples/
+
+For example:
+ ./generate . ../../specs/amqp.0-9.xml samples/Proxy.rb
+will generate
+
+
+
+
+
+
+
+
+
diff --git a/qpid/cpp/rubygen/amqpgen.rb b/qpid/cpp/rubygen/amqpgen.rb
new file mode 100755
index 0000000000..bf473506d4
--- /dev/null
+++ b/qpid/cpp/rubygen/amqpgen.rb
@@ -0,0 +1,501 @@
+#
+# Generic AMQP code generation library.
+#
+
+# TODO aconway 2008-02-21:
+#
+# The amqp_attr_reader and amqp_child_reader for each Amqp* class
+# should correspond exactly to ampq.dtd. Currently they are more
+# permissive so we can parse 0-10 preview and 0-10 final XML.
+#
+# Code marked with "# preview" should be removed/modified when final 0-10
+# is complete and we are ready to remove preview-related code.
+#
+
+require 'delegate'
+require 'rexml/document'
+require 'pathname'
+include REXML
+
+# Handy String functions for converting names.
+class String
+ # Convert to CapitalizedForm.
+ def caps() gsub( /(^|\W)(\w)/ ) { |m| $2.upcase } end
+
+ # Convert to underbar_separated_form.
+ def bars() tr('- .','_'); end
+
+ # Convert to ALL_UPPERCASE_FORM
+ def shout() bars.upcase!; end
+
+ # Convert to lowerCaseCapitalizedForm
+ def lcaps() gsub( /\W(\w)/ ) { |m| $1.upcase } end
+
+ def plural() self + (/[xs]$/ === self ? 'es' : 's'); end
+end
+
+# Sort an array by name.
+module Enumerable
+ def sort_by_name() sort { |a,b| a.name <=> b.name }; end
+end
+
+# Add functions similar to attr_reader for AMQP attributes/children.
+# Symbols that are ruby Object function names (e.g. class) get
+# an "_" suffix.
+class Module
+ # Add trailing _ to avoid conflict with Object methods.
+ def mangle(sym)
+ (Object.method_defined? sym) ? (sym.to_s+"_").intern : sym
+ end
+
+ # Add attribute reader for XML attribute.
+ def amqp_attr_reader(*attrs)
+ attrs.each { |a|
+ case a
+ when Symbol
+ define_method(mangle(a)) {
+ @amqp_attr_reader||={ }
+ @amqp_attr_reader[a] ||= xml.attributes[a.to_s]
+ }
+ when Hash
+ a.each { |attr, default|
+ define_method(mangle(attr)) {
+ @amqp_attr_reader||={ }
+ value = xml.attributes[attr.to_s]
+ if value
+ @amqp_attr_reader[attr] ||= value
+ else
+ @amqp_attr_reader[attr] ||= default
+ end
+ }
+ }
+ end
+ }
+ end
+
+ # Add 2 child readers:
+ # elname(name) == child('elname',name)
+ # elnames() == children('elname')
+ def amqp_child_reader(*element_names)
+ element_names.each { |e|
+ define_method(mangle(e)) { |name| child(e.to_s, name) }
+ define_method(mangle(e.to_s.plural)) { children(e.to_s) } }
+ end
+
+ # When there can only be one child instance
+ def amqp_single_child_reader(*element_names)
+ element_names.each { |e|
+ define_method(mangle(e)) { children(e.to_s)[0] } }
+ end
+end
+
+
+# An AmqpElement contains an XML element and provides a convenient
+# API to access AMQP data.
+#
+# NB: AmqpElements cache values from XML, they assume that
+# the XML model does not change after the AmqpElement has
+# been created.
+class AmqpElement
+
+ def wrap(xml)
+ return nil if ["assert","rule"].include? xml.name
+ eval("Amqp"+xml.name.caps).new(xml, self) or raise "nil wrapper"
+ end
+
+ public
+
+ def initialize(xml, parent)
+ @xml, @parent=xml, parent
+ @children=xml.elements.map { |e| wrap e }.compact
+ @cache_child={}
+ @cache_children={}
+ @cache_children[nil]=@children
+ end
+
+ attr_reader :parent, :xml, :children, :doc
+ amqp_attr_reader :name, :label
+
+ # List of children of type elname, or all children if elname
+ # not specified.
+ def children(elname=nil)
+ if elname
+ @cache_children[elname] ||= @children.select { |c| elname==c.xml.name }
+ else
+ @children
+ end
+ end
+
+ def each_descendant(&block)
+ yield self
+ @children.each { |c| c.each_descendant(&block) }
+ end
+
+ def collect_all(amqp_type)
+ collect=[]
+ each_descendant { |d| collect << d if d.is_a? amqp_type }
+ collect
+ end
+
+ # Look up child of type elname with attribute name.
+ def child(elname, name)
+ @cache_child[[elname,name]] ||= children(elname).find { |c| c.name==name }
+ end
+
+ # The root <amqp> element.
+ def root() @root ||=parent ? parent.root : self; end
+
+ # Are we in preview or final 0-10
+ # preview - used to make some classes behave differently for preview vs. final
+ def final?() root().version == "0-10"; end
+
+ def to_s() "#<#{self.class}(#{name})>"; end
+ def inspect() to_s; end
+
+ # Text of doc child if there is one.
+ def doc() d=xml.elements["doc"]; d and d.text; end
+
+ def fqname()
+ throw "fqname: #{self} #{parent.fqname} has no name" unless name
+ p=parent && parent.fqname
+ p ? p+"."+name : name;
+ end
+
+ def containing_class()
+ return self if is_a? AmqpClass
+ return parent && parent.containing_class
+ end
+
+end
+
+class AmqpResponse < AmqpElement
+ def initialize(xml, parent) super; end
+ def fqname() (parent ? parent.dotted_name+"." : "") + "response"; end
+end
+
+class AmqpDoc < AmqpElement
+ def initialize(xml,parent) super; end
+ def text() @xml.text end
+end
+
+class AmqpChoice < AmqpElement
+ def initialize(xml,parent) super; end
+ amqp_attr_reader :name, :value
+end
+
+class AmqpEnum < AmqpElement
+ def initialize(xml,parent) super; end
+ amqp_child_reader :choice
+end
+
+# 0-10 array domains are missing element type information, add it here.
+ArrayTypes={
+ "str16-array" => "str-16",
+ "amqp-host-array" => "connection.amqp-host-url",
+ "command-fragments" => "session.command-fragment",
+ "in-doubt" => "dtx.xid"
+}
+
+class AmqpDomain < AmqpElement
+ def initialize(xml, parent)
+ super
+ root.used_by[uses].push(fqname) if uses and uses.index('.')
+ end
+
+ amqp_attr_reader :type
+ amqp_single_child_reader :struct # preview
+ amqp_single_child_reader :enum
+
+ def uses() type_=="array" ? ArrayTypes[name] : type_; end
+
+ def unalias()
+ d=self
+ while (d.type_ != d.name and root.domain(d.type_))
+ d=root.domain(d.type_)
+ end
+ return d
+ end
+end
+
+class AmqpException < AmqpElement
+ def initialize(xml, amqp) super; end;
+ amqp_attr_reader :error_code
+end
+
+class AmqpField < AmqpElement
+ def initialize(xml, amqp)
+ super;
+ root.used_by[type_].push(parent.fqname) if type_ and type_.index('.')
+ end
+
+ def domain() root.domain(xml.attributes["domain"]); end
+ amqp_single_child_reader :struct # preview
+ amqp_child_reader :exception
+ amqp_attr_reader :type, :default, :code, :required
+end
+
+class AmqpChassis < AmqpElement # preview
+ def initialize(xml, parent) super; end
+ amqp_attr_reader :implement
+end
+
+class AmqpConstant < AmqpElement
+ def initialize(xml, parent) super; end
+ amqp_attr_reader :value, :class
+end
+
+class AmqpResult < AmqpElement
+ def initialize(xml, parent) super; end
+ amqp_single_child_reader :struct # preview
+ amqp_attr_reader :type
+ def name() "result"; end
+end
+
+class AmqpEntry < AmqpElement
+ def initialize(xml,parent) super; end
+ amqp_attr_reader :type
+end
+
+class AmqpHeader < AmqpElement
+ def initialize(xml,parent) super; end
+ amqp_child_reader :entry
+ amqp_attr_reader :required
+end
+
+class AmqpBody < AmqpElement
+ def initialize(xml,parent) super; end
+ amqp_attr_reader :required
+end
+
+class AmqpSegments < AmqpElement
+ def initialize(xml,parent) super; end
+ amqp_child_reader :header, :body
+end
+
+class AmqpStruct < AmqpElement
+ def initialize(xml, parent) super; end
+ amqp_attr_reader :type # preview
+ amqp_attr_reader :size, :code, :pack
+ amqp_child_reader :field
+
+ # preview - preview code needs default "short" for pack.
+ alias :raw_pack :pack
+ def pack() raw_pack or (not parent.final? and "short"); end
+ def result?() parent.xml.name == "result"; end
+ def domain?() parent.xml.name == "domain"; end
+end
+
+class AmqpMethod < AmqpElement
+ def initialize(xml, parent) super; end
+
+ amqp_attr_reader :content, :index, :synchronous
+ amqp_child_reader :field, :chassis,:response
+ amqp_single_child_reader :result
+
+ def on_chassis?(chassis) child("chassis", chassis); end
+ def on_client?() on_chassis? "client"; end
+ def on_server?() on_chassis? "server"; end
+end
+
+class AmqpImplement < AmqpElement
+ def initialize(xml,amqp) super; end
+ amqp_attr_reader :handle, :send
+end
+
+class AmqpRole < AmqpElement
+ def initialize(xml,amqp) super; end
+ amqp_attr_reader :implement
+end
+
+# Base class for command and control.
+class AmqpAction < AmqpElement
+ def initialize(xml,amqp) super; end
+ amqp_child_reader :implement, :field, :response
+ amqp_attr_reader :code
+ def size() "4" end # Encoded as a size 4 Struct
+end
+
+class AmqpControl < AmqpAction
+ def initialize(xml,amqp) super; end
+end
+
+class AmqpCommand < AmqpAction
+ def initialize(xml,amqp) super; end
+ amqp_child_reader :exception
+ amqp_single_child_reader :result, :segments
+end
+
+class AmqpClass < AmqpElement
+ def initialize(xml,amqp) super; end
+
+ amqp_attr_reader :index # preview
+ amqp_child_reader :method # preview
+
+ amqp_child_reader :struct, :domain, :control, :command, :role
+ amqp_attr_reader :code
+
+ # chassis should be "client" or "server"
+ def methods_on(chassis) # preview
+ @methods_on ||= { }
+ @methods_on[chassis] ||= methods_.select { |m| m.on_chassis? chassis }
+ end
+
+ def l4?() # preview
+ !["connection", "session", "execution"].include?(name)
+ end
+
+ def control?()
+ ["connection010", "session010"].include?(name)
+ end
+
+ def actions() controls+commands; end
+end
+
+class AmqpType < AmqpElement
+ def initialize(xml,amqp) super; end
+ amqp_attr_reader :code, :fixed_width, :variable_width
+end
+
+class AmqpXref < AmqpElement
+ def initialize(xml,amqp) super; end
+end
+
+# AMQP root element.
+class AmqpRoot < AmqpElement
+ amqp_attr_reader :major, :minor, :port, :comment
+ amqp_child_reader :doc, :type, :struct, :domain, :constant, :class
+
+ def get_root(x)
+ case x
+ when Element then x
+ when Document then x.root
+ else Document.new(x).root
+ end
+ end
+
+ # Initialize with output directory and spec files from ARGV.
+ def initialize(*specs)
+ raise "No XML spec files." if specs.empty?
+ xml=get_root(specs.shift)
+ specs.each { |s| xml_merge(xml, get_root(s)) }
+ @used_by=Hash.new{ |h,k| h[k]=[] }
+ super(xml, nil)
+ end
+
+ attr_reader :used_by
+
+ def merge(root) xml_merge(xml, root.xml); end
+
+ def version() major + "-" + minor; end
+
+ # preview - only struct child reader remains for new mapping
+ def domain_structs() domains.map{ |d| d.struct }.compact; end
+ def result_structs()
+ methods_.map { |m| m.result and m.result.struct }.compact
+ end
+ def structs() result_structs+domain_structs; end
+
+ def methods_() classes.map { |c| c.methods_ }.flatten; end
+
+ #preview
+ # Return all methods on chassis for all classes.
+ def methods_on(chassis)
+ @methods_on ||= { }
+ @methods_on[chassis] ||= classes.map { |c| c.methods_on(chassis) }.flatten
+ end
+
+ def fqname() nil; end
+
+ private
+
+ # Merge contents of elements.
+ def xml_merge(to,from)
+ from.elements.each { |from_child|
+ tag,name = from_child.name, from_child.attributes["name"]
+ to_child=to.elements["./#{tag}[@name='#{name}']"]
+ to_child ? xml_merge(to_child, from_child) : to.add(from_child.deep_clone) }
+ end
+end
+
+# Collect information about generated files.
+class GenFiles
+ @@files =[]
+ def GenFiles.add(f) @@files << f; end
+ def GenFiles.get() @@files; end
+end
+
+# Base class for code generators.
+# Supports setting a per-line prefix, useful for e.g. indenting code.
+#
+class Generator
+ # Takes directory for output or "-", meaning print file names that
+ # would be generated.
+ def initialize (outdir, amqp)
+ @amqp=amqp
+ @outdir=outdir
+ @prefix=[''] # For indentation or comments.
+ @indentstr=' ' # One indent level.
+ @outdent=2
+ Pathname.new(@outdir).mkpath unless @outdir=="-"
+ end
+
+ # Create a new file, set @out.
+ def file(file, &block)
+ GenFiles.add file
+ if (@outdir != "-")
+ @path=Pathname.new "#{@outdir}/#{file}"
+ @path.parent.mkpath
+ @out=String.new # Generate in memory first
+ if block then yield; endfile; end
+ end
+ end
+
+ def endfile()
+ if @outdir != "-"
+ if @path.exist? and @path.read == @out
+ puts "Skipped #{@path} - unchanged" # Dont generate if unchanged
+ else
+ @path.open('w') { |f| f << @out }
+ puts "Generated #{@path}"
+ end
+ end
+ end
+
+ # Append multi-line string to generated code, prefixing each line.
+ def gen(str)
+ str.each_line { |line|
+ @out << @prefix.last unless @midline
+ @out << line
+ @midline = nil
+ }
+ # Note if we stopped mid-line
+ @midline = /[^\n]\z/ === str
+ end
+
+ # Append str + '\n' to generated code.
+ def genl(str="") gen str+"\n"; end
+
+ # Generate code with added prefix.
+ def prefix(add, &block)
+ @prefix.push @prefix.last+add
+ if block then yield; endprefix; end
+ end
+
+ def endprefix()
+ @prefix.pop
+ end
+
+ # Generate indented code
+ def indent(n=1,&block) prefix(@indentstr * n,&block); end
+ alias :endindent :endprefix
+
+ # Generate outdented code
+ def outdent(&block)
+ @prefix.push @prefix.last[0...-2]
+ if block then yield; endprefix; end
+ end
+ alias :endoutdent :endprefix
+
+ attr_accessor :out
+end
+
diff --git a/qpid/cpp/rubygen/cppgen.rb b/qpid/cpp/rubygen/cppgen.rb
new file mode 100755
index 0000000000..757894163d
--- /dev/null
+++ b/qpid/cpp/rubygen/cppgen.rb
@@ -0,0 +1,390 @@
+#!/usr/bin/ruby
+#
+# General purpose C++ code generation.
+#
+require 'amqpgen'
+require 'set'
+
+Copyright=<<EOS
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.
+///
+
+
+EOS
+
+CppKeywords = Set.new(["and", "and_eq", "asm", "auto", "bitand",
+ "bitor", "bool", "break", "case", "catch", "char",
+ "class", "compl", "const", "const_cast", "continue",
+ "default", "delete", "do", "DomainInfo", "double",
+ "dynamic_cast", "else", "enum", "explicit", "extern",
+ "false", "float", "for", "friend", "goto", "if",
+ "inline", "int", "long", "mutable", "namespace", "new",
+ "not", "not_eq", "operator", "or", "or_eq", "private",
+ "protected", "public", "register", "reinterpret_cast",
+ "return", "short", "signed", "sizeof", "static",
+ "static_cast", "struct", "switch", "template", "this",
+ "throw", "true", "try", "typedef", "typeid",
+ "typename", "union", "unsigned", "using", "virtual",
+ "void", "volatile", "wchar_t", "while", "xor",
+ "xor_eq"])
+# Names that need a trailing "_" to avoid clashes.
+CppMangle = CppKeywords+Set.new(["string"])
+
+class String
+ def cppsafe() CppMangle.include?(self) ? self+"_" : self; end
+
+ def amqp2cpp()
+ path=split(".")
+ name=path.pop
+ return name.typename if path.empty?
+ path.map! { |n| n.nsname }
+ return (path << name.caps.cppsafe).join("::")
+ end
+
+ def typename() caps.cppsafe; end
+ def nsname() bars.cppsafe; end
+ def constname() shout.cppsafe; end
+ def funcname() lcaps.cppsafe; end
+ def varname() lcaps.cppsafe; end
+end
+
+# Hold information about a C++ type.
+#
+# preview - new mapping does not use CppType,
+# Each amqp type corresponds exactly by dotted name
+# to a type, domain or struct, which in turns
+# corresponds by name to a C++ type or typedef.
+# (see String.amqp2cpp)
+#
+class CppType
+ def initialize(name) @name=@param=@ret=name; end
+ attr_reader :name, :param, :ret, :code
+
+ def retref() @ret="#{name}&"; self; end
+ def retcref() @ret="const #{name}&"; self; end
+ def passcref() @param="const #{name}&"; self; end
+ def code(str) @code=str; self; end
+ def defval(str) @defval=str; self; end
+
+ def encode(value, buffer)
+ @code ? "#{buffer}.put#{@code}(#{value});" : "#{value}.encode(#{buffer});"
+ end
+
+ def decode(value,buffer)
+ if @code
+ if /&$/===param then
+ "#{buffer}.get#{@code}(#{value});"
+ else
+ "#{value} = #{buffer}.get#{@code}();"
+ end
+ else
+ "#{value}.decode(#{buffer});"
+ end
+ end
+
+ def default_value()
+ return @defval ||= "#{name}()"
+ end
+
+ def to_s() name; end;
+end
+
+class AmqpElement
+ # convert my amqp type_ attribute to a C++ type.
+ def amqp2cpp()
+ return "ArrayDomain<#{ArrayTypes[name].amqp2cpp}> " if type_=="array"
+ return type_.amqp2cpp
+ end
+end
+
+class AmqpField
+ def cppname() name.lcaps.cppsafe; end
+ def cpptype() domain.cpptype; end
+ def bit?() domain.type_ == "bit"; end
+ def signature() cpptype.param+" "+cppname; end
+ def fqtypename()
+ unless type_.index(".")
+ c=containing_class
+ return c.domain(type_).fqtypename if c.domain(type_)
+ return c.struct(type_).fqclassname if c.struct(type_)
+ end
+ return amqp2cpp
+ end
+ def paramtype()
+ /^(int|uint|char|boolean|bit)/ === type_ ? fqtypename : "const #{fqtypename}&"
+ end
+ def param_default() "=#{fqtypename}()" end
+end
+
+class AmqpMethod
+ def cppname() name.lcaps.cppsafe; end
+ def param_names() fields.map { |f| f.cppname }; end
+ def signature() fields.map { |f| f.signature }; end
+ def body_name() parent.name.caps+name.caps+"Body"; end
+
+ def cpp_pack_type() # preview
+ CppType.new("uint16_t").code("Short").defval("0");
+ end
+ def pack() # preview
+ "short"
+ end
+end
+
+module AmqpHasFields
+ def parameters(with_default=nil)
+ fields.map { |f|
+ "#{f.paramtype} #{f.cppname}_#{f.param_default if with_default}"
+ }
+ end
+ def unused_parameters() fields.map { |f| "#{f.paramtype} /*#{f.cppname}_*/"} end
+ def arguments() fields.map { |f| "#{f.cppname}_"} end
+ def values() fields.map { |f| "#{f.cppname}"} end
+ def initializers() fields.map { |f| "#{f.cppname}(#{f.cppname}_)"} end
+end
+
+class AmqpAction
+ def classname() name.typename; end
+ def funcname() parent.name.funcname + name.caps; end
+ def fqclassname() parent.name+"::"+classname; end
+ def full_code() (containing_class.code.hex << 8)+code.hex; end
+ include AmqpHasFields
+end
+
+class AmqpType
+ def typename() name.typename; end
+ def fixed?() fixed_width; end
+end
+
+class AmqpCommand < AmqpAction
+ def base() "Command"; end
+end
+
+class AmqpControl < AmqpAction
+ def base() "Control"; end
+end
+
+class AmqpClass
+ def cppname() name.caps; end # preview
+ def nsname() name.nsname; end
+end
+
+class AmqpDomain
+ @@typemap = {
+ "bit"=> CppType.new("bool").code("Octet").defval("false"),
+ "octet"=>CppType.new("uint8_t").code("Octet").defval("0"),
+ "short"=>CppType.new("uint16_t").code("Short").defval("0"),
+ "long"=>CppType.new("uint32_t").code("Long").defval("0"),
+ "longlong"=>CppType.new("uint64_t").code("LongLong").defval("0"),
+ "timestamp"=>CppType.new("uint64_t").code("LongLong").defval("0"),
+ "longstr"=>CppType.new("string").passcref.retcref.code("LongString"),
+ "shortstr"=>CppType.new("string").passcref.retcref.code("ShortString"),
+ "mediumstr"=>CppType.new("string").passcref.retcref.code("MediumString"),
+ "table"=>CppType.new("FieldTable").passcref.retcref,
+ "array"=>CppType.new("Array").passcref.retcref,
+ "content"=>CppType.new("Content").passcref.retcref,
+ "rfc1982-long-set"=>CppType.new("SequenceNumberSet").passcref.retcref,
+ "sequence-set"=>CppType.new("SequenceSet").passcref.retcref,
+ "long-struct"=>CppType.new("string").passcref.retcref.code("LongString"),
+ "uuid"=>CppType.new("Uuid").passcref.retcref
+ }
+
+ def cppname() name.caps; end
+
+ def fqtypename()
+ return containing_class.nsname+"::"+name.typename if containing_class
+ name.typename
+ end
+
+ def cpptype()
+ d=unalias
+ @cpptype ||= @@typemap[d.type_] or
+ CppType.new(d.cppname).passcref.retcref or
+ raise "Invalid type #{self}"
+ end
+
+ def AmqpDomain.lookup_type(t)
+ @@typemap[t]
+ end
+end
+
+class AmqpResult
+ def cpptype()
+ @cpptype=CppType.new(parent.parent.name.caps+parent.name.caps+"Result").passcref
+ end
+end
+
+class AmqpStruct
+ include AmqpHasFields
+
+ def cpp_pack_type() # preview
+ AmqpDomain.lookup_type(pack()) or CppType.new("uint16_t");
+ end
+ def cpptype() parent.cpptype; end # preview
+ def cppname() cpptype.name; end # preview
+ def fqclassname() containing_class.nsname+"::"+name.typename; end
+ def classname() name.typename; end
+ def full_code() (containing_class.code.hex << 8)+code.hex; end
+end
+
+class CppGen < Generator
+ def initialize(outdir, *specs)
+ super(outdir,*specs)
+ # need to sort classes for dependencies
+ @actions=[] # Stack of end-scope actions
+ end
+
+ # Write a header file.
+ def h_file(path, &block)
+ path = (/\.h$/ === path ? path : path+".h")
+ guard=path.upcase.tr('./-','_')
+ file(path) {
+ gen "#ifndef #{guard}\n"
+ gen "#define #{guard}\n"
+ gen Copyright
+ yield
+ gen "#endif /*!#{guard}*/\n"
+ }
+ end
+
+ # Write a .cpp file.
+ def cpp_file(path, &block)
+ path = (/\.cpp$/ === path ? path : path+".cpp")
+ file(path) do
+ gen Copyright
+ yield
+ end
+ end
+
+ def include(header)
+ header+=".h" unless /(\.h|[">])$/===header
+ header="\"#{header}\"" unless /(^<.*>$)|(^".*"$)/===header
+ genl "#include #{header}"
+ end
+
+ def scope(open="{",close="}", &block)
+ genl open
+ indent &block
+ genl close
+ end
+
+ def namespace(name, &block)
+ genl
+ names = name.split("::")
+ names.each { |n| genl "namespace #{n} {" }
+ genl "namespace {" if (names.empty?)
+ genl
+ yield
+ genl
+ genl('}'*([names.size, 1].max)+" // namespace "+name)
+ genl
+ end
+
+ def struct_class(type, name, bases, &block)
+ gen "#{type} #{name}"
+ if (!bases.empty?)
+ genl ":"
+ indent { gen "#{bases.join(",\n")}" }
+ end
+ genl
+ scope("{","};", &block)
+ end
+
+ def struct(name, *bases, &block)
+ struct_class("struct", name, bases, &block);
+ end
+ def cpp_class(name, *bases, &block)
+ struct_class("class", name, bases, &block);
+ end
+
+ def typedef(type, name) genl "typedef #{type} #{name};\n"; end
+
+ def variant(types) "boost::variant<#{types.join(", ")}>"; end
+ def variantl(types) "boost::variant<#{types.join(", \n")}>"; end
+ def blank_variant(types) variant(["boost::blank"]+types); end
+ def tuple(types) "boost::tuple<#{types.join(', ')}>"; end
+
+ def public() outdent { genl "public:" } end
+ def private() outdent { genl "private:" } end
+ def protected() outdent { genl "protected:" } end
+
+ # Returns [namespace, classname, filename]
+ def parse_classname(full_cname)
+ names=full_cname.split("::")
+ return names[0..-2].join('::'), names[-1], names.join("/")
+ end
+
+ def doxygen_comment(&block)
+ genl "/**"
+ prefix(" * ",&block)
+ genl " */"
+ end
+
+ # Generate code in namespace for each class
+ def each_class_ns()
+ @amqp.classes.each { |c| namespace(c.nsname) { yield c } }
+ end
+
+ def signature(ret_name, params, trailer="")
+ if params.size <= 1
+ genl ret_name+"(#{params})"+trailer
+ else
+ scope(ret_name+"(",")"+trailer) { genl params.join(",\n") }
+ end
+ end
+
+ def function_decl(ret_name, params=[], trailer="")
+ signature(ret_name, params, trailer+";")
+ end
+
+ def function_defn(ret_name, params=[], trailer="")
+ genl
+ signature(ret_name, params, trailer)
+ scope() { yield }
+ end
+
+ def ctor_decl(name, params=[]) function_decl(name, params); end
+
+ def ctor_defn(name, params=[], inits=[])
+ signature(name, params, inits.empty? ? "" : " :")
+ indent { gen inits.join(",\n") } if not inits.empty?
+ scope() { yield }
+ end
+
+ def function_call(name, params=[], trailer="")
+ gen name
+ list "(",params, ")"
+ gen trailer
+ end
+end
+
+# Fully-qualified class name
+class FqClass < Struct.new(:fqname,:namespace,:name,:file)
+ def initialize(fqclass)
+ names=fqclass.split "::"
+ super(fqclass, names[0..-2].join('::'), names[-1], names.join("/"))
+ end
+end
+
diff --git a/qpid/cpp/rubygen/generate b/qpid/cpp/rubygen/generate
new file mode 100755
index 0000000000..9f0ddf0f1c
--- /dev/null
+++ b/qpid/cpp/rubygen/generate
@@ -0,0 +1,103 @@
+#!/usr/bin/env ruby
+require 'pathname'
+require 'amqpgen'
+
+#
+# Run a set of code generation templates.
+#
+if ARGV.size < 3
+ puts <<EOS
+Usage: #{ARGV[0]} OUTDIR SPEC.xml [ ... ] TEMPLATE.rb [ ... ]
+or: #{ARGV[0]} OUTDIR SPEC.xml [ ... ] all [ makefragment.mk ]
+
+Parse all SPEC.xml files to create an AMQP model, run each TEMPLATE
+putting the resulting files under OUTDIR. Prints a list of files
+generated to standard output.
+
+If OUTDIR is '-' then just prints file list without generating files.
+EOS
+ exit 1
+end
+
+# Create array of specs by version
+def parse_specs(files)
+ lists=Hash.new { |h,k| h[k]=[] }
+ files.each { |f|
+ spec=AmqpRoot.new(File.new(f))
+ lists[spec.version] << spec
+ }
+ specs={}
+ lists.each_pair { |k,l|
+ specs[k] = l.size==1 ? l.first : AmqpRoot.new(*l.map { |s| s.xml})
+ }
+ return specs
+end
+
+# Run selected templates
+if ARGV.any? { |arg| arg=="all" }
+ templates=Dir["#{File.dirname __FILE__}/*/*.rb"]
+else
+ templates=ARGV.grep(/\.rb$/)
+end
+
+$outdir=ARGV[0]
+$models=parse_specs(ARGV.grep(/\.xml$/))
+templates.each { |t|
+ ver=Pathname.new(t).dirname.basename.to_s
+ $amqp=$models[ver]
+ if $amqp
+ load t
+ else
+ puts "Warning: skipping #{t}, no spec file for version #{ver}."
+ end
+}
+
+def make_continue(lines) lines.join(" \\\n "); end
+
+# Generate makefile
+makefile=ARGV.grep(/.mk$/)[0]
+if makefile
+ dir=Dir.getwd
+ Dir.chdir File.dirname(__FILE__)
+ generator_files=Dir["**/*.rb"] << File.basename(__FILE__)
+ Dir.chdir dir
+ rgen_generator=generator_files.map{ |f| "$(rgen_dir)/#{f}" }
+ rgen_srcs=GenFiles.get.map{ |f| "#{$outdir}/#{f}" }
+
+ File.open(makefile, 'w') { |out|
+ out << <<EOS
+# Generated makefile fragment.
+# Including makefile defines $(rgen_dir) $(rgen_cmd) and $(specs).
+
+rgen_generator=#{make_continue rgen_generator}
+
+rgen_client_cpp=#{make_continue(rgen_srcs.grep(%r|/qpid/client/.+\.cpp$|))}
+
+rgen_common_cpp=#{make_continue(rgen_srcs.grep(%r{qpid/(framing|amqp_.+)/.+\.cpp$}))}
+
+rgen_srcs=#{make_continue rgen_srcs}
+
+# Header file install rules.
+EOS
+ ["amqp_0_10", "framing", "client/no_keyword","client", "broker"].each { |ns|
+ dir="qpid/#{ns}"
+ dir_ = dir.tr("/", "_")
+ regex=%r|#{dir}/[^/]+\.h$|
+ out << <<EOS
+#{dir_}dir = $(includedir)/#{dir}
+dist_#{dir_}_HEADERS = #{make_continue rgen_srcs.grep(regex)}
+
+EOS
+ }
+ out << <<EOS
+if GENERATE
+$(srcdir)/#{File.basename makefile}: $(rgen_generator) $(specs)
+ $(rgen_cmd)
+
+# Empty rule in case a generator file is renamed/removed.
+$(rgen_generator):
+endif
+EOS
+ }
+end
+
diff --git a/qpid/cpp/src/Makefile.am b/qpid/cpp/src/Makefile.am
new file mode 100644
index 0000000000..a31dbdfa9d
--- /dev/null
+++ b/qpid/cpp/src/Makefile.am
@@ -0,0 +1,502 @@
+SUBDIRS = . tests
+
+EXTRA_DIST= $(platform_dist) $(rgen_srcs)
+
+## 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_PREVIEW_XML and AMQP_FINAL_XML are defined in ../configure.ac
+amqp_99_0_xml=@AMQP_PREVIEW_XML@ $(top_srcdir)/xml/extra.xml $(top_srcdir)/xml/cluster.xml
+amqp_0_10_xml=@AMQP_FINAL_XML@
+specs=$(amqp_99_0_xml) $(amqp_0_10_xml)
+
+# Ruby generator.
+rgen_dir=$(top_srcdir)/rubygen
+rgen_cmd=ruby -I $(rgen_dir) $(rgen_dir)/generate $(srcdir)/gen $(specs) all $(srcdir)/rubygen.mk
+
+# Management generator.
+mgen_dir=$(top_srcdir)/managementgen
+mgen_cmd=$(mgen_dir)/main.py -m $(srcdir)/managementgen.mk \
+ $(top_srcdir)/../specs/management-schema.xml \
+ $(top_srcdir)/../specs/management-types.xml \
+ $(mgen_dir)/templates $(srcdir)/gen/qpid/management
+
+endif # GENERATE
+
+include $(srcdir)/rubygen.mk
+include $(srcdir)/managementgen.mk
+
+DISTCLEANFILES=rubygen.mk 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_LDADD = \
+ libqpidbroker.la \
+ libqpidcommon.la
+
+sbin_PROGRAMS = qpidd
+qpidd_SOURCES = qpidd.cpp
+
+posix_plat_src = \
+ qpid/sys/epoll/EpollPoller.cpp \
+ qpid/sys/DeletionManager.h \
+ qpid/sys/posix/Socket.cpp \
+ qpid/sys/posix/AsynchIO.cpp \
+ qpid/sys/posix/Time.cpp \
+ qpid/sys/posix/Thread.cpp \
+ qpid/sys/posix/Shlib.cpp
+
+posix_plat_hdr = \
+ qpid/sys/posix/check.h \
+ qpid/sys/posix/Condition.h \
+ qpid/sys/posix/PrivatePosix.h \
+ qpid/sys/posix/Mutex.h \
+ qpid/sys/posix/Thread.h
+
+platform_src = $(posix_plat_src)
+platform_hdr = $(posix_plat_hdr)
+
+lib_LTLIBRARIES = libqpidcommon.la libqpidbroker.la libqpidclient.la
+
+include cluster.mk
+
+# The logger library uses boost::date_time to format time.
+# We have to disable the unused parameters warning to get around
+# unused parameters in boost::date_time headers. So we build it
+# in a convenience library to link into libqpid_common.
+#
+noinst_LTLIBRARIES=libLogger.la
+libLogger_la_SOURCES=qpid/log/Logger.cpp qpid/log/Logger.h
+libLogger_la_CXXFLAGS=$(AM_CXXFLAGS) -Wno-unused-parameter
+
+libqpidcommon_la_LIBADD = \
+ -lboost_program_options \
+ -lboost_filesystem \
+ -luuid \
+ libLogger.la \
+ $(LIB_DLOPEN) \
+ $(LIB_CLOCK_GETTIME)
+
+libqpidcommon_la_SOURCES = \
+ $(rgen_common_cpp) \
+ $(platform_src) \
+ qpid/amqp_0_10/apply.h \
+ qpid/amqp_0_10/all_built_in_types.h \
+ qpid/amqp_0_10/built_in_types.h \
+ qpid/amqp_0_10/complex_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/Header.h \
+ 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/Unit.h \
+ qpid/amqp_0_10/Unit.cpp \
+ qpid/amqp_0_10/UnknownType.h \
+ qpid/amqp_0_10/UnknownType.cpp \
+ qpid/Serializer.h \
+ 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/FieldTable.cpp \
+ qpid/framing/FieldValue.cpp \
+ qpid/framing/FramingContent.cpp \
+ qpid/framing/FrameSet.cpp \
+ qpid/framing/ProtocolInitiation.cpp \
+ qpid/framing/ProtocolVersion.cpp \
+ qpid/framing/SessionState.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/assert.cpp qpid/assert.h \
+ qpid/Exception.cpp \
+ qpid/Plugin.cpp \
+ qpid/Url.cpp \
+ qpid/sys/AggregateOutput.cpp \
+ qpid/sys/AsynchIOAcceptor.cpp \
+ qpid/sys/Dispatcher.cpp \
+ qpid/sys/Runnable.cpp \
+ qpid/sys/SystemInfo.cpp \
+ qpid/sys/Serializer.cpp \
+ qpid/sys/Shlib.cpp \
+ qpid/DataDir.cpp \
+ qpid/Options.cpp \
+ qpid/log/Options.cpp \
+ qpid/log/Selector.cpp \
+ qpid/log/Statement.cpp \
+ qpid/IList.h \
+ qpid/ISList.h \
+ qpid/pointer_to_other.h
+
+libqpidbroker_la_LIBADD = libqpidcommon.la -lboost_iostreams
+libqpidbroker_la_SOURCES = \
+ $(mgen_broker_cpp) \
+ qpid/amqp_0_10/Connection.h \
+ qpid/amqp_0_10/Connection.cpp \
+ qpid/broker/Broker.cpp \
+ qpid/broker/BrokerAdapter.cpp \
+ qpid/broker/SessionAdapter.cpp \
+ qpid/broker/BrokerSingleton.cpp \
+ qpid/broker/Exchange.cpp \
+ qpid/broker/Queue.cpp \
+ qpid/broker/PersistableMessage.cpp \
+ qpid/broker/Bridge.cpp \
+ qpid/broker/PreviewConnection.cpp \
+ qpid/broker/PreviewConnectionCodec.cpp \
+ qpid/broker/PreviewConnectionHandler.cpp \
+ qpid/broker/PreviewSessionHandler.cpp \
+ qpid/broker/PreviewSessionManager.cpp \
+ qpid/broker/PreviewSessionState.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/DtxHandlerImpl.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/IncomingExecutionContext.cpp \
+ qpid/broker/IncompleteMessageList.cpp \
+ qpid/broker/Message.cpp \
+ qpid/broker/MessageAdapter.cpp \
+ qpid/broker/MessageBuilder.cpp \
+ qpid/broker/MessageDelivery.cpp \
+ qpid/broker/MessageHandlerImpl.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/RecoveryManagerImpl.cpp \
+ qpid/broker/RecoveredEnqueue.cpp \
+ qpid/broker/RecoveredDequeue.cpp \
+ qpid/broker/SemanticState.h \
+ qpid/broker/SemanticState.cpp \
+ qpid/broker/SessionState.h \
+ qpid/broker/SessionState.cpp \
+ qpid/broker/SessionManager.h \
+ qpid/broker/SessionManager.cpp \
+ qpid/broker/SessionHandler.h \
+ qpid/broker/SessionContext.h \
+ qpid/broker/SessionHandler.cpp \
+ qpid/broker/SemanticHandler.cpp \
+ qpid/broker/System.cpp \
+ qpid/broker/Timer.cpp \
+ qpid/broker/TopicExchange.cpp \
+ qpid/broker/TxAccept.cpp \
+ qpid/broker/TxAck.cpp \
+ qpid/broker/TxBuffer.cpp \
+ qpid/broker/TxPublish.cpp \
+ qpid/broker/Vhost.cpp \
+ qpid/management/Manageable.cpp \
+ qpid/management/ManagementAgent.cpp \
+ qpid/management/ManagementExchange.cpp \
+ qpid/management/ManagementObject.cpp
+
+libqpidclient_la_LIBADD = libqpidcommon.la
+libqpidclient_la_SOURCES = \
+ $(rgen_client_cpp) \
+ qpid/client/SessionBase.cpp \
+ qpid/client/Connection.cpp \
+ qpid/client/Channel.cpp \
+ qpid/client/Exchange.cpp \
+ qpid/broker/PersistableMessage.cpp \
+ qpid/client/Queue.cpp \
+ qpid/client/ConnectionImpl.cpp \
+ qpid/client/Connector.cpp \
+ qpid/client/Demux.cpp \
+ qpid/client/Dispatcher.cpp \
+ qpid/client/LocalQueue.cpp \
+ qpid/client/MessageListener.cpp \
+ qpid/client/Correlator.cpp \
+ qpid/client/CompletionTracker.cpp \
+ qpid/client/ConnectionHandler.cpp \
+ qpid/client/ExecutionHandler.cpp \
+ qpid/client/FutureCompletion.cpp \
+ qpid/client/FutureResponse.cpp \
+ qpid/client/FutureResult.cpp \
+ qpid/client/SessionCore.cpp \
+ qpid/client/StateManager.cpp \
+ qpid/client/SubscriptionManager.cpp
+
+nobase_include_HEADERS = \
+ $(platform_hdr) \
+ qpid/amqp_0_10/apply.h \
+ qpid/assert.h \
+ qpid/DataDir.h \
+ qpid/Exception.h \
+ qpid/amqp_0_10/Exception.h \
+ qpid/Msg.h \
+ qpid/Options.h \
+ qpid/Plugin.h \
+ qpid/ptr_map.h \
+ qpid/RefCounted.h \
+ qpid/SharedObject.h \
+ qpid/Url.h \
+ qpid/InlineVector.h \
+ qpid/InlineAllocator.h \
+ qpid/memory.h \
+ qpid/shared_ptr.h \
+ qpid/broker/Broker.h \
+ qpid/broker/BrokerAdapter.h \
+ qpid/broker/SessionAdapter.h \
+ qpid/broker/Exchange.h \
+ qpid/broker/Queue.h \
+ qpid/broker/BrokerSingleton.h \
+ qpid/broker/Bridge.h \
+ qpid/broker/PreviewConnection.h \
+ qpid/broker/PreviewConnectionCodec.h \
+ qpid/broker/PreviewConnectionHandler.h \
+ qpid/broker/PreviewSessionHandler.h \
+ qpid/broker/PreviewSessionManager.h \
+ qpid/broker/PreviewSessionState.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/DeliveryToken.h \
+ qpid/broker/DirectExchange.h \
+ qpid/broker/DtxAck.h \
+ qpid/broker/DtxBuffer.h \
+ qpid/broker/DtxHandlerImpl.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/IncomingExecutionContext.h \
+ qpid/broker/IncompleteMessageList.h \
+ qpid/broker/Message.h \
+ qpid/broker/MessageAdapter.h \
+ qpid/broker/MessageBuilder.h \
+ qpid/broker/MessageDelivery.h \
+ qpid/broker/MessageHandlerImpl.h \
+ qpid/broker/MessageStore.h \
+ qpid/broker/MessageStoreModule.h \
+ qpid/broker/NameGenerator.h \
+ qpid/broker/NullMessageStore.h \
+ qpid/broker/Persistable.h \
+ qpid/broker/PersistableExchange.h \
+ qpid/broker/PersistableMessage.h \
+ qpid/broker/PersistableQueue.h \
+ qpid/broker/Prefetch.h \
+ qpid/broker/QueueBindings.h \
+ qpid/broker/QueuePolicy.h \
+ qpid/broker/QueueRegistry.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/SemanticHandler.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/TxAck.h \
+ qpid/broker/TxBuffer.h \
+ qpid/broker/TxOp.h \
+ qpid/broker/TxPublish.h \
+ qpid/broker/Vhost.h \
+ qpid/client/AckMode.h \
+ qpid/client/ChainableFrameHandler.h \
+ qpid/client/Channel.h \
+ qpid/client/Exchange.h \
+ qpid/client/Message.h \
+ qpid/client/Queue.h \
+ qpid/client/AckPolicy.h \
+ qpid/client/Completion.h \
+ qpid/client/CompletionTracker.h \
+ qpid/client/Connection.h \
+ qpid/client/ConnectionHandler.h \
+ qpid/client/ConnectionImpl.h \
+ qpid/client/Connector.h \
+ qpid/client/Correlator.h \
+ qpid/client/Demux.h \
+ qpid/client/Dispatcher.h \
+ qpid/client/LocalQueue.h \
+ qpid/client/Execution.h \
+ qpid/client/ExecutionHandler.h \
+ qpid/client/Future.h \
+ qpid/client/FutureCompletion.h \
+ qpid/client/FutureResponse.h \
+ qpid/client/FutureResult.h \
+ qpid/client/MessageListener.h \
+ qpid/client/MessageQueue.h \
+ qpid/client/Response.h \
+ qpid/client/SessionBase.h \
+ qpid/client/Session.h \
+ qpid/client/SessionCore.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/Buffer.h \
+ qpid/framing/ChannelHandler.h \
+ qpid/framing/FieldTable.h \
+ qpid/framing/FieldValue.h \
+ qpid/framing/FrameDefaultVisitor.h \
+ qpid/framing/FrameHandler.h \
+ qpid/framing/FrameHandler.h \
+ qpid/framing/FrameSet.h \
+ qpid/framing/FramingContent.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/BodyHolder.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/SessionState.h \
+ qpid/framing/SendContent.h \
+ qpid/framing/SequenceNumber.h \
+ qpid/framing/SequenceSet.h \
+ qpid/framing/SequenceNumberSet.h \
+ qpid/framing/SerializeHandler.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/Selector.h \
+ qpid/log/Statement.h \
+ qpid/management/Args.h \
+ qpid/management/Manageable.h \
+ qpid/management/ManagementAgent.h \
+ qpid/management/ManagementExchange.h \
+ qpid/management/ManagementObject.h \
+ qpid/sys/Acceptor.h \
+ qpid/sys/AggregateOutput.h \
+ qpid/sys/AsynchIO.h \
+ qpid/sys/AtomicCount.h \
+ qpid/sys/BlockingQueue.h \
+ qpid/sys/Condition.h \
+ qpid/sys/ConnectionInputHandler.h \
+ qpid/sys/ConnectionInputHandlerFactory.h \
+ qpid/sys/ConnectionOutputHandler.h \
+ qpid/sys/Dispatcher.h \
+ qpid/sys/Module.h \
+ qpid/sys/Monitor.h \
+ qpid/sys/Mutex.h \
+ qpid/sys/OutputControl.h \
+ qpid/sys/ConnectionCodec.h \
+ qpid/sys/OutputTask.h \
+ qpid/sys/Poller.h \
+ qpid/sys/Runnable.h \
+ qpid/sys/ScopedIncrement.h \
+ qpid/sys/Semaphore.h \
+ qpid/sys/Serializer.h \
+ qpid/sys/SystemInfo.h \
+ qpid/sys/Shlib.h \
+ qpid/sys/ShutdownHandler.h \
+ qpid/sys/Socket.h \
+ qpid/sys/StateMonitor.h \
+ qpid/sys/Waitable.h \
+ qpid/sys/Thread.h \
+ qpid/sys/Time.h \
+ qpid/sys/TimeoutHandler.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/qpid/cpp/src/cluster.mk b/qpid/cpp/src/cluster.mk
new file mode 100644
index 0000000000..9503845b92
--- /dev/null
+++ b/qpid/cpp/src/cluster.mk
@@ -0,0 +1,24 @@
+#
+# Cluster library makefile fragment, to be included in Makefile.am
+#
+lib_LTLIBRARIES += libqpidcluster.la
+
+if CPG
+
+libqpidcluster_la_SOURCES = \
+ 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/ClassifierHandler.h \
+ qpid/cluster/ClassifierHandler.cpp
+
+libqpidcluster_la_LIBADD= -lcpg libqpidbroker.la
+
+else
+# Empty stub library to satisfy rpm spec file.
+libqpidcluster_la_SOURCES =
+
+endif
diff --git a/qpid/cpp/src/generate.sh b/qpid/cpp/src/generate.sh
new file mode 100755
index 0000000000..3582893f24
--- /dev/null
+++ b/qpid/cpp/src/generate.sh
@@ -0,0 +1,48 @@
+# !/bin/sh
+# 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/qpid/cpp/src/prof b/qpid/cpp/src/prof
new file mode 100755
index 0000000000..bd889a1446
--- /dev/null
+++ b/qpid/cpp/src/prof
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+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/qpid/cpp/src/qpid/DataDir.cpp b/qpid/cpp/src/qpid/DataDir.cpp
new file mode 100644
index 0000000000..abf9b061e4
--- /dev/null
+++ b/qpid/cpp/src/qpid/DataDir.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 "Exception.h"
+#include "DataDir.h"
+#include "qpid/log/Statement.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <cerrno>
+
+namespace qpid {
+
+DataDir::DataDir (std::string path) :
+ enabled (!path.empty ()),
+ dirPath (path)
+{
+ if (!enabled)
+ {
+ QPID_LOG (info, "No data directory - Disabling persistent configuration");
+ return;
+ }
+
+ const char *cpath = dirPath.c_str ();
+ struct stat s;
+
+ if (::stat (cpath, &s))
+ throw Exception ("Data directory not found: " + path);
+
+ std::string lockFile (path);
+ lockFile = lockFile + "/lock";
+ int fd = ::open (lockFile.c_str (), O_CREAT | O_EXCL,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (fd == -1)
+ {
+ if (errno == EEXIST)
+ throw Exception ("Data directory is locked by another process");
+ if (errno == EACCES)
+ throw Exception ("Insufficient privileges for data directory");
+
+ std::ostringstream oss;
+ oss << "Error locking data directory: errno=" << errno;
+ throw Exception (oss.str ());
+ }
+
+ QPID_LOG (info, "Locked data directory: " << dirPath);
+}
+
+DataDir::~DataDir ()
+{
+ if (dirPath.empty ())
+ return;
+
+ std::string lockFile (dirPath);
+ lockFile = lockFile + "/lock";
+
+ ::unlink (lockFile.c_str ());
+ QPID_LOG (info, "Unlocked data directory: " << dirPath);
+}
+
+} // namespace qpid
+
diff --git a/qpid/cpp/src/qpid/DataDir.h b/qpid/cpp/src/qpid/DataDir.h
new file mode 100644
index 0000000000..56aa4f26d7
--- /dev/null
+++ b/qpid/cpp/src/qpid/DataDir.h
@@ -0,0 +1,47 @@
+#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>
+
+namespace qpid {
+
+/**
+ * DataDir class.
+ */
+class DataDir
+{
+ const bool enabled;
+ const std::string dirPath;
+
+ public:
+
+ DataDir (std::string path);
+ ~DataDir ();
+
+ bool isEnabled () { return enabled; }
+ std::string getPath () { return dirPath; }
+};
+
+} // namespace qpid
+
+#endif /*!QPID_DATADIR_H*/
diff --git a/qpid/cpp/src/qpid/Exception.cpp b/qpid/cpp/src/qpid/Exception.cpp
new file mode 100644
index 0000000000..a69955c9dc
--- /dev/null
+++ b/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 <errno.h>
+#include <assert.h>
+#include <string.h>
+
+namespace qpid {
+
+std::string strError(int err) {
+ char buf[512];
+ return std::string(strerror_r(err, buf, sizeof(buf)));
+}
+
+Exception::Exception(const std::string& msg) throw() : message(msg) {
+ QPID_LOG(debug, "Exception thrown: " << message);
+}
+
+Exception::~Exception() throw() {}
+
+std::string Exception::getPrefix() const { return "Exception"; }
+
+const char* Exception::what() const throw() {
+ if (whatStr.empty())
+ whatStr = getPrefix() + ": " + 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/qpid/cpp/src/qpid/Exception.h b/qpid/cpp/src/qpid/Exception.h
new file mode 100644
index 0000000000..2f934166a7
--- /dev/null
+++ b/qpid/cpp/src/qpid/Exception.h
@@ -0,0 +1,86 @@
+#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/Msg.h"
+
+#include <memory>
+#include <string>
+
+namespace qpid
+{
+
+/** Get the error message for a system number err, e.g. errno. */
+std::string strError(int err);
+
+/**
+ * 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();
+
+ protected:
+ std::string getPrefix() const;
+ private:
+ std::string message;
+ mutable std::string whatStr;
+};
+
+/**
+ * I have made SessionException a common base for Channel- and
+ * Connection- Exceptions. This is not strictly correct but allows all
+ * model layer exceptions to be handled as SessionExceptions which is
+ * how they are classified in the final 0-10 specification. I.e. this
+ * is a temporary hack to allow the preview and final codepaths to
+ * co-exist with minimal changes.
+ */
+
+struct SessionException : public Exception {
+ const framing::ReplyCode code;
+ SessionException(framing::ReplyCode code_, const std::string& message)
+ : Exception(message), code(code_) {}
+};
+
+struct ChannelException : public SessionException {
+ ChannelException(framing::ReplyCode code, const std::string& message)
+ : SessionException(code, message) {}
+};
+
+struct ConnectionException : public SessionException {
+ ConnectionException(framing::ReplyCode code, const std::string& message)
+ : SessionException(code, message) {}
+};
+
+struct ClosedException : public Exception {
+ ClosedException(const std::string& msg=std::string());
+ std::string getPrefix() const;
+};
+
+} // namespace qpid
+
+#endif /*!_Exception_*/
diff --git a/qpid/cpp/src/qpid/IList.h b/qpid/cpp/src/qpid/IList.h
new file mode 100644
index 0000000000..f5c78ced68
--- /dev/null
+++ b/qpid/cpp/src/qpid/IList.h
@@ -0,0 +1,196 @@
+#ifndef QPID_ILIST_H
+#define QPID_ILIST_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 "ISList.h"
+
+namespace qpid {
+
+template <class> class IList;
+
+/** Base class for values (nodes) in an IList.
+ *@param raw or smart-pointer type to use for the "next" pointer.
+ * Using a smart pointer like shared_ptr or intrusive_ptr
+ * will automate memory management.
+ */
+template <class Pointer> class IListNode {
+ public:
+ typedef Pointer pointer;
+ typedef typename Pointee<Pointer>::type NodeType;
+ typedef typename pointer_to_other<Pointer, const NodeType>::type const_pointer;
+
+ protected:
+ IListNode() : prev() {}
+ IListNode(const IListNode&) {} // Don't copy next/prev pointers
+
+ pointer getNext() { return next; }
+ const_pointer getNext() const { return next; }
+ pointer getPrev() { return prev; }
+ const_pointer getPrev() const { return prev; }
+
+ private:
+ pointer prev, next;
+ friend class IList<NodeType>;
+};
+
+
+/**
+ * Intrusive doubly-linked list.
+ *
+ * Provides bidirectional iterator and constant time insertion
+ * at front and back.
+ *
+ * The list itself performs no memory management. Use a smart pointer
+ * as the pointer type (e.g. intrusive_ptr, shared_ptr) for automated
+ * memory management.
+ *
+ * Unlike standard containers insert(), push_front() and push_back()
+ * take const pointer& rather than const value_type&.
+ *
+ * Iterators can be converted to the pointer type.
+ *
+ * Noncopyable - intrusively linked nodes cannot be shared between
+ * lists. Does provide swap()
+ *
+ * @param Node value type for the list, must derive from ISListNode<>.
+ */
+template<class Node> class IList {
+ template <class> class Iterator;
+ public:
+ typedef Node value_type;
+ typedef typename Node::pointer pointer;
+ typedef typename Node::const_pointer const_pointer;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef Iterator<value_type> iterator;
+ typedef Iterator<const value_type> const_iterator;
+
+ IList() : begin_(), last_() {}
+
+ iterator begin() { return begin_; }
+ const_iterator begin() const { return begin_; }
+ iterator end() { return 0; }
+ const_iterator end() const { return 0; }
+
+ bool empty() const { return begin() == end(); }
+
+ size_type size() const {
+ int s = 0;
+ for (const_iterator i=begin(); i != end(); ++i)
+ ++s;
+ return s;
+ }
+
+ void swap(IList &x) { swap(begin_, x.begin_); swap(last_, x.last_); }
+
+ iterator insert(iterator i, const pointer& p) {
+ if (empty()) {
+ begin_ = last_ = p;
+ insert(0, p, 0);
+ }
+ else if (i) {
+ insert(i->prev, p, i);
+ if (i == begin_) --begin_;
+ }
+ else {
+ insert(last_, p, 0) ;
+ last_ = p;
+ }
+ return p;
+ }
+
+ void erase(iterator i) {
+ if (begin_ == last_)
+ begin_ = last_ = 0;
+ else {
+ if (i == begin_) ++begin_;
+ else i->prev->next = i->next;
+ if (i == last_) --last_;
+ else i->next->prev = i->prev;
+ }
+ i->prev = i->next = pointer(0);
+ }
+
+ void erase(iterator i, iterator j) { while(i != j) erase(i); }
+ void clear() { while (!empty()) { erase(begin()); } }
+
+ reference front() { return *begin(); }
+ const_reference front() const { return *begin(); }
+ void push_front(const pointer& p) { insert(begin(), p); }
+ void pop_front() { erase(begin()); }
+
+ /** Iterator to the last element in the list. */
+ iterator last() { return last_; }
+ const_iterator last() const { return last_; }
+
+ reference back() { return *last(); }
+ const_reference back() const { return *last(); }
+ void push_back(const pointer& p) { insert(end(), p); }
+ void pop_back() { erase(last()); }
+
+ private:
+ void insert(pointer a, pointer b, pointer c) {
+ b->prev = a;
+ if (a) a->next = b;
+ b->next = c;
+ if (c) c->prev = b;
+ }
+
+ template <class T>
+ class Iterator : public boost::iterator_facade<
+ Iterator<T>, T, boost::bidirectional_traversal_tag>
+ {
+ public:
+ Iterator() : ptr() {};
+
+ template <class U> Iterator(
+ const Iterator<U>& i,
+ typename boost::enable_if_convertible<U*, T*>::type* = 0
+ ) : ptr(i.ptr) {}
+
+ operator pointer() { return ptr; }
+ operator const_pointer() const { return ptr; }
+
+ private:
+ friend class boost::iterator_core_access;
+
+ Iterator(const_pointer p) : ptr(const_cast<pointer>(p)) {};
+
+ T& dereference() const { return *ptr; }
+ void increment() { ptr = ptr->next; }
+ void decrement() { ptr = ptr->prev; }
+ bool equal(const Iterator& x) const { return ptr == x.ptr; }
+
+ pointer ptr;
+
+ friend class IList<Node>;
+ };
+
+ iterator begin_, last_;
+};
+
+} // namespace qpid
+
+#endif /*!QPID_ILIST_H*/
diff --git a/qpid/cpp/src/qpid/ISList.h b/qpid/cpp/src/qpid/ISList.h
new file mode 100644
index 0000000000..96ba3ec726
--- /dev/null
+++ b/qpid/cpp/src/qpid/ISList.h
@@ -0,0 +1,176 @@
+#ifndef QPID_ISLIST_H
+#define QPID_ISLIST_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/iterator/iterator_adaptor.hpp>
+#include <boost/noncopyable.hpp>
+#include "pointer_to_other.h"
+
+namespace qpid {
+
+template <class Pointer> struct Pointee {
+ typedef typename Pointer::element_type type;
+};
+
+template <class T> struct Pointee<T*> {
+ typedef T type;
+};
+
+template <class> class ISList;
+template <class> class IList;
+
+/** Base class for values (nodes) in an ISList.
+ *@param raw or smart-pointer type to use for the "next" pointer.
+ * Using a smart pointer like shared_ptr or intrusive_ptr
+ * will automate memory management.
+ */
+template <class Pointer> class ISListNode {
+ public:
+ typedef Pointer pointer;
+ typedef typename Pointee<Pointer>::type NodeType;
+ typedef typename pointer_to_other<Pointer, const NodeType>::type const_pointer;
+
+ protected:
+ ISListNode() : next() {}
+ ISListNode(const ISListNode&) {} // Don't copy the next pointer.
+
+ pointer getNext() { return next; }
+ const_pointer getNext() const { return next; }
+
+ private:
+ pointer next;
+ friend class ISList<NodeType>;
+};
+
+
+/**
+ * Intrusive singly-linked list.
+ *
+ * Provides forward iterator, constant time insertion and constant
+ * time pop_front (but not pop_back) so makes a good queue
+ * implementation.
+ *
+ * Unlike standard containers insert(), push_front() and push_back()
+ * take const pointer& rather than const value_type&.
+ *
+ * Iterators can be converted to pointers.
+ *
+ * Noncopyable - intrusively linked nodes cannot be shared.
+ *
+ * @param Node value type for the list, must derive from ISListNode<T>.
+ */
+template <class Node> class ISList : private boost::noncopyable {
+ template <class> class Iterator;
+ public:
+ typedef Node value_type;
+ typedef typename Node::pointer pointer;
+ typedef typename Node::const_pointer const_pointer;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef Iterator<value_type> iterator;
+ typedef Iterator<const value_type> const_iterator;
+
+ ISList() : first(pointer()), end_(&first) {}
+
+ iterator begin() { return iterator(&first); }
+ const_iterator begin() const { return const_iterator(&first); }
+ iterator end() { return end_; }
+ const_iterator end() const { return end_; }
+
+ bool empty() const { return begin() == end(); }
+
+ size_type size() const {
+ int s = 0;
+ for (const_iterator i=begin(); i != end(); ++i)
+ ++s;
+ return s;
+ }
+
+ void swap(ISList &x) { swap(first, x.first); swap(end_, x.end_); }
+
+ /** Unlike standard containers, insert takes a const pointer&, not a
+ * const value_type&. The value is not copied, only linked into the list.
+ */
+ iterator insert(iterator i, const pointer& p) {
+ p->next = *(i.pptr);
+ *(i.pptr) = p;
+ if (i==end_) ++end_;
+ return i;
+ }
+
+ void erase(iterator i) {
+ if (&i->next == end_.pptr)
+ end_ = i;
+ *(i.pptr) = (**(i.pptr)).next;
+ }
+
+ void erase(iterator i, iterator j) { while(i != j) erase(i); }
+ void clear() { while (!empty()) { erase(begin()); } }
+
+ reference front() { return *begin(); }
+ const_reference front() const { return *begin(); }
+ void pop_front() { erase(begin()); }
+ void push_front(pointer x) { insert(begin(), x); }
+
+ void push_back(pointer x) { insert(end(), x); }
+
+ private:
+ template <class T>
+ class Iterator : public boost::iterator_facade <
+ Iterator<T>, T, boost::forward_traversal_tag>
+ {
+ public:
+ Iterator() {};
+
+ template <class U> Iterator(
+ const Iterator<U>& i,
+ typename boost::enable_if_convertible<U*, T*>::type* = 0
+ ) : pptr(i.pptr) {}
+
+ operator pointer() { return *pptr; }
+ operator const_pointer() const { return *pptr; }
+
+ private:
+ friend class boost::iterator_core_access;
+
+ Iterator(const pointer* pp) : pptr(const_cast<pointer*>(pp)) {};
+
+ T& dereference() const { return **pptr; }
+ void increment() { pptr = &(**pptr).next; }
+ bool equal(const Iterator& x) const { return pptr == x.pptr; }
+
+ pointer* pptr;
+
+ friend class ISList<Node>;
+ };
+
+ private:
+ pointer first;
+ iterator end_;
+};
+
+} // namespace qpid
+
+#endif /*!QPID_ISLIST_H*/
diff --git a/qpid/cpp/src/qpid/InlineAllocator.h b/qpid/cpp/src/qpid/InlineAllocator.h
new file mode 100644
index 0000000000..0bb30fa1a4
--- /dev/null
+++ b/qpid/cpp/src/qpid/InlineAllocator.h
@@ -0,0 +1,69 @@
+#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>
+
+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) {}
+
+ pointer allocate(size_type n) {
+ if (n <= Max && !allocated) {
+ allocated=true;
+ return store;
+ }
+ else
+ return BaseAllocator::allocate(n, 0);
+ }
+
+ void deallocate(pointer p, size_type n) {
+ if (p == store) 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:
+ value_type store[Max];
+ bool allocated;
+};
+
+} // namespace qpid
+
+#endif /*!QPID_INLINEALLOCATOR_H*/
diff --git a/qpid/cpp/src/qpid/InlineVector.h b/qpid/cpp/src/qpid/InlineVector.h
new file mode 100644
index 0000000000..551b9912e7
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/Msg.h b/qpid/cpp/src/qpid/Msg.h
new file mode 100644
index 0000000000..7214db611f
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/Options.cpp b/qpid/cpp/src/qpid/Options.cpp
new file mode 100644
index 0000000000..a5d3b54dd6
--- /dev/null
+++ b/qpid/cpp/src/qpid/Options.cpp
@@ -0,0 +1,160 @@
+/*
+ *
+ * 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;
+
+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());
+ 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();
+ }
+ return string();
+ }
+
+ string configFileLine (string& line) {
+ size_t pos = line.find ('=');
+ if (pos == string::npos)
+ return string();
+ string key = line.substr (0, pos);
+ 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";
+ return string ();
+ }
+
+ 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) {}
+
+void Options::parse(int argc, char** 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) {
+ // 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);
+ }
+ 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 (find_nothrow("help", false))
+ msg << "Use --help to see valid options" << endl;
+ 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");
+}
+
+} // namespace qpid
+
diff --git a/qpid/cpp/src/qpid/Options.h b/qpid/cpp/src/qpid/Options.h
new file mode 100644
index 0000000000..475d8e91d5
--- /dev/null
+++ b/qpid/cpp/src/qpid/Options.h
@@ -0,0 +1,150 @@
+#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>
+
+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
+ */
+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());
+
+ boost::program_options::options_description_easy_init addOptions() {
+ return add_options();
+ }
+
+ /**
+ * 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** argv,
+ const std::string& configfile=std::string(),
+ bool allowUnknown = false);
+};
+
+/**
+ * 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/qpid/cpp/src/qpid/Plugin.cpp b/qpid/cpp/src/qpid/Plugin.cpp
new file mode 100644
index 0000000000..d38b53a56e
--- /dev/null
+++ b/qpid/cpp/src/qpid/Plugin.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 "Plugin.h"
+
+namespace qpid {
+
+Plugin::Plugins Plugin::plugins;
+
+Plugin::Plugin() {
+ // Register myself.
+ plugins.push_back(this);
+}
+
+Plugin::~Plugin() {}
+
+Options* Plugin::getOptions() { return 0; }
+
+const Plugin::Plugins& Plugin::getPlugins() {
+ return plugins;
+}
+
+} // namespace qpid
diff --git a/qpid/cpp/src/qpid/Plugin.h b/qpid/cpp/src/qpid/Plugin.h
new file mode 100644
index 0000000000..e040662866
--- /dev/null
+++ b/qpid/cpp/src/qpid/Plugin.h
@@ -0,0 +1,98 @@
+#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 "qpid/shared_ptr.h"
+#include <boost/noncopyable.hpp>
+#include <vector>
+#include <boost/function.hpp>
+
+
+/**@file Generic plug-in framework. */
+
+namespace qpid {
+class Options;
+
+/**
+ * Plug-in base class.
+ */
+class Plugin : boost::noncopyable
+{
+ public:
+ /**
+ * Base interface for targets that receive plug-ins.
+ *
+ * The Broker is a plug-in target, there might be others
+ * in future.
+ */
+ struct Target { virtual ~Target() {} };
+
+ typedef std::vector<Plugin*> Plugins;
+
+ /**
+ * Construct 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 static
+ * 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.
+ * 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.
+ * 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();
+
+ private:
+ static Plugins plugins;
+};
+
+} // namespace qpid
+
+#endif /*!QPID_PLUGIN_H*/
diff --git a/qpid/cpp/src/qpid/RefCounted.h b/qpid/cpp/src/qpid/RefCounted.h
new file mode 100644
index 0000000000..d67f6c31db
--- /dev/null
+++ b/qpid/cpp/src/qpid/RefCounted.h
@@ -0,0 +1,78 @@
+#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() {};
+};
+
+/**
+ * Reference-counted member of a reference-counted parent class.
+ * Delegates reference counts to the parent so that the parent is
+ * deleted only when there are no references to the parent or any of
+ * its children.
+ * TODO: Delete this class if it's unused as I don't think this class makes much sense:
+ */
+struct RefCountedChild {
+ RefCounted& parent;
+
+protected:
+ RefCountedChild(RefCounted& parent_) : parent(parent_) {}
+
+public:
+ void addRef() const { parent.addRef(); }
+ void release() const { parent.release(); }
+};
+
+} // 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(); }
+inline void intrusive_ptr_add_ref(const qpid::RefCountedChild* p) { p->addRef(); }
+inline void intrusive_ptr_release(const qpid::RefCountedChild* p) { p->release(); }
+}
+
+
+#endif /*!QPID_REFCOUNTED_H*/
diff --git a/qpid/cpp/src/qpid/Serializer.h b/qpid/cpp/src/qpid/Serializer.h
new file mode 100644
index 0000000000..fc53097207
--- /dev/null
+++ b/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 getLimit() 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/qpid/cpp/src/qpid/SharedObject.h b/qpid/cpp/src/qpid/SharedObject.h
new file mode 100644
index 0000000000..852a036ab9
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/Url.cpp b/qpid/cpp/src/qpid/Url.cpp
new file mode 100644
index 0000000000..090cbb712a
--- /dev/null
+++ b/qpid/cpp/src/qpid/Url.cpp
@@ -0,0 +1,176 @@
+/*
+ *
+ * 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 <limits.h> // NB: must be before boost/spirit headers.
+#include <boost/spirit.hpp>
+#include <boost/spirit/actor.hpp>
+
+#include <sstream>
+
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <errno.h>
+
+using namespace boost::spirit;
+using namespace std;
+
+namespace qpid {
+
+std::ostream& operator<<(std::ostream& os, const TcpAddress& a) {
+ return os << "tcp:" << a.host << ":" << a.port;
+}
+
+std::istream& operator>>(std::istream&, const TcpAddress&);
+
+Url Url::getHostNameUrl(uint16_t port) {
+ char name[HOST_NAME_MAX];
+ if (::gethostname(name, sizeof(name)) != 0)
+ throw InvalidUrl(QPID_MSG("Cannot get host name: " << strError(errno)));
+ return Url(TcpAddress(name, port));
+}
+
+static const string LOCALHOST("127.0.0.1");
+
+Url Url::getIpAddressesUrl(uint16_t port) {
+ Url url;
+ 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)
+ url.push_back(TcpAddress(addr, port));
+ }
+ close (s);
+ 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;
+}
+
+// Addition to boost::spirit parsers: accept any character from a
+// string. Vastly more compile-time-efficient than long rules of the
+// form: ch_p('x') | ch_p('y') |...
+//
+struct ch_in : public char_parser<ch_in> {
+ ch_in(const string& chars_) : chars(chars_) {}
+ bool test(char ch_) const {
+ return chars.find(ch_) != string::npos;
+ }
+ string chars;
+};
+
+inline ch_in ch_in_p(const string& chars) {
+ return ch_in(chars);
+}
+
+/** Grammar for AMQP URLs. */
+struct UrlGrammar : public grammar<UrlGrammar>
+{
+ Url& addr;
+
+ UrlGrammar(Url& addr_) : addr(addr_) {}
+
+ template <class ScannerT>
+ struct definition {
+ TcpAddress tcp;
+
+ definition(const UrlGrammar& self)
+ {
+ first = eps_p[clear_a(self.addr)] >> amqp_url;
+ amqp_url = str_p("amqp:") >> prot_addr_list >>
+ !(str_p("/") >> !parameters);
+ prot_addr_list = prot_addr % ',';
+ prot_addr = tcp_prot_addr; // Extend for TLS etc.
+
+ // TCP addresses
+ tcp_prot_addr = tcp_id >> tcp_addr[push_back_a(self.addr, tcp)];
+ tcp_id = !str_p("tcp:");
+ tcp_addr = !(host[assign_a(tcp.host)] >> !(':' >> port));
+
+ // See http://www.apps.ietf.org/rfc/rfc3986.html#sec-A
+ // for real host grammar. Shortcut:
+ port = uint_parser<uint16_t>()[assign_a(tcp.port)];
+ host = *( unreserved | pct_encoded );
+ unreserved = alnum_p | ch_in_p("-._~");
+ pct_encoded = "%" >> xdigit_p >> xdigit_p;
+ parameters = *anychar_p >> end_p; // Ignore, not used yet.
+ }
+
+ const rule<ScannerT>& start() const { return first; }
+
+ rule<ScannerT> first, amqp_url, prot_addr_list, prot_addr,
+ tcp_prot_addr, tcp_id, tcp_addr, host, port,
+ unreserved, pct_encoded, parameters;
+ };
+};
+
+void Url::parse(const char* url) {
+ cache.clear();
+ if (!boost::spirit::parse(url, UrlGrammar(*this)).full)
+ throw InvalidUrl(string("Invalid AMQP url: ")+url);
+}
+
+void Url::parseNoThrow(const char* url) {
+ cache.clear();
+ if (!boost::spirit::parse(url, UrlGrammar(*this)).full)
+ clear();
+}
+
+void Url::throwIfEmpty() const {
+ throw InvalidUrl("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/qpid/cpp/src/qpid/Url.h b/qpid/cpp/src/qpid/Url.h
new file mode 100644
index 0000000000..20f42db0ad
--- /dev/null
+++ b/qpid/cpp/src/qpid/Url.h
@@ -0,0 +1,109 @@
+#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/Exception.h"
+#include <boost/variant.hpp>
+#include <string>
+#include <vector>
+#include <new>
+#include <ostream>
+
+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)
+ : host(host_), port(port_) {}
+ std::string host;
+ uint16_t port;
+};
+
+inline bool operator==(const TcpAddress& x, const TcpAddress& y) {
+ return y.host==x.host && y.port == x.port;
+}
+
+std::ostream& operator<<(std::ostream& os, const TcpAddress& a);
+
+/** Address is a variant of all address types, more coming in future. */
+typedef boost::variant<TcpAddress> Address;
+
+/** 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 InvalidUrl : public Exception {
+ InvalidUrl(const std::string& s) : Exception(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 InvalidUrl if invalid. */
+ explicit Url(const std::string& url) { parse(url.c_str()); }
+
+ /** Parse url, throw InvalidUrl if invalid. */
+ explicit Url(const char* url) { parse(url); }
+
+ template<class T> Url& operator=(T s) { parse(s); return *this; }
+
+ /** Throw InvalidUrl 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 InvalidUrl 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/qpid/cpp/src/qpid/amqp_0_10/Array.cpp b/qpid/cpp/src/qpid/amqp_0_10/Array.cpp
new file mode 100644
index 0000000000..380e0f1f36
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/amqp_0_10/Array.h b/qpid/cpp/src/qpid/amqp_0_10/Array.h
new file mode 100644
index 0000000000..8061a99b43
--- /dev/null
+++ b/qpid/cpp/src/qpid/amqp_0_10/Array.h
@@ -0,0 +1,120 @@
+#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); s(this->begin(), this->end()); }
+
+ template <class S> void encode(S& s) const {
+ s(contentSize())(CodeForType<T>::value)(uint32_t(this->size()));
+ }
+
+ 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);
+ s.setLimit(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);
+ }
+
+ 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); s(this->begin(), this->end()); }
+
+ template <class S> void encode(S& s) const {
+ s(contentSize())(type)(uint32_t(this->size()));
+ }
+
+ 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);
+ s.setLimit(size);
+ s(type)(count);
+ this->clear();
+ this->resize(count, UnknownType(type));
+ }
+
+ 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/qpid/cpp/src/qpid/amqp_0_10/Body.h b/qpid/cpp/src/qpid/amqp_0_10/Body.h
new file mode 100644
index 0000000000..c96931551c
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/amqp_0_10/Codec.h b/qpid/cpp/src/qpid/amqp_0_10/Codec.h
new file mode 100644
index 0000000000..5cad5cf4ed
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/amqp_0_10/Connection.cpp b/qpid/cpp/src/qpid/amqp_0_10/Connection.cpp
new file mode 100644
index 0000000000..c5315ccf4c
--- /dev/null
+++ b/qpid/cpp/src/qpid/amqp_0_10/Connection.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 "Connection.h"
+#include "qpid/log/Statement.h"
+#include "qpid/amqp_0_10/exceptions.h"
+
+namespace qpid {
+namespace amqp_0_10 {
+
+using sys::Mutex;
+
+Connection::Connection(sys::OutputControl& o, broker::Broker& broker, const std::string& id)
+ : frameQueueClosed(false), output(o), connection(this, broker, id),
+ identifier(id), initialized(false) {}
+
+size_t Connection::decode(const char* buffer, size_t size) {
+ framing::Buffer in(const_cast<char*>(buffer), size);
+ 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 !initialized || !frameQueue.empty();
+}
+
+bool Connection::isClosed() const {
+ Mutex::ScopedLock l(frameQueueLock);
+ return frameQueueClosed;
+}
+
+size_t Connection::encode(const char* buffer, size_t size) {
+ Mutex::ScopedLock l(frameQueueLock);
+ framing::Buffer out(const_cast<char*>(buffer), size);
+ if (!initialized) {
+ framing::ProtocolInitiation pi(getVersion());
+ pi.encode(out);
+ initialized = true;
+ }
+ while (!frameQueue.empty() && (frameQueue.front().size() <= out.available())) {
+ frameQueue.front().encode(out);
+ QPID_LOG(trace, "SENT [" << identifier << "]: " << frameQueue.front());
+ frameQueue.pop();
+ }
+ assert(frameQueue.empty() || frameQueue.front().size() <= size);
+ if (!frameQueue.empty() && frameQueue.front().size() > size)
+ throw InternalErrorException(QPID_MSG("Could not write frame, too large for buffer."));
+ return out.getPosition();
+}
+
+void Connection::activateOutput() { output.activateOutput(); }
+
+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(f);
+ }
+ activateOutput();
+}
+
+framing::ProtocolVersion Connection::getVersion() const {
+ return framing::ProtocolVersion(0,10);
+}
+
+}} // namespace qpid::amqp_0_10
diff --git a/qpid/cpp/src/qpid/amqp_0_10/Connection.h b/qpid/cpp/src/qpid/amqp_0_10/Connection.h
new file mode 100644
index 0000000000..e4672be722
--- /dev/null
+++ b/qpid/cpp/src/qpid/amqp_0_10/Connection.h
@@ -0,0 +1,62 @@
+#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 "qpid/sys/ConnectionCodec.h"
+#include "qpid/sys/ConnectionOutputHandler.h"
+#include "qpid/sys/Mutex.h"
+#include "Connection.h"
+#include "qpid/broker/Connection.h"
+#include <queue>
+
+namespace qpid {
+namespace broker { class Broker; }
+namespace amqp_0_10 {
+
+// FIXME aconway 2008-03-18: Update to 0-10.
+class Connection : public sys::ConnectionCodec,
+ public sys::ConnectionOutputHandler
+{
+ std::queue<framing::AMQFrame> frameQueue;
+ bool frameQueueClosed;
+ mutable sys::Mutex frameQueueLock;
+ sys::OutputControl& output;
+ broker::Connection connection; // FIXME aconway 2008-03-18:
+ std::string identifier;
+ bool initialized;
+
+ public:
+ Connection(sys::OutputControl&, broker::Broker&, const std::string& id);
+ 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 closed(); // connection closed by peer.
+ void close(); // closing from this end.
+ void send(framing::AMQFrame&);
+ framing::ProtocolVersion getVersion() const;
+};
+
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_BROKER_CONNECTION_H*/
diff --git a/qpid/cpp/src/qpid/amqp_0_10/Decimal.h b/qpid/cpp/src/qpid/amqp_0_10/Decimal.h
new file mode 100644
index 0000000000..50fc457c76
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/amqp_0_10/Exception.h b/qpid/cpp/src/qpid/amqp_0_10/Exception.h
new file mode 100644
index 0000000000..4841d91215
--- /dev/null
+++ b/qpid/cpp/src/qpid/amqp_0_10/Exception.h
@@ -0,0 +1,186 @@
+#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::ConnectionException {
+ // 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::ConnectionException(c,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::SessionException {
+ // 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::SessionException(code, 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*/
+#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 Exception {
+ typedef connection::CloseCode Code;
+ ConnectionException(Code c, const std::string m)
+ : 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 Exception {
+ SessionException(const std::string& msg) : Exception(msg) {}
+};
+
+/** Raised when the state of a session has been destroyed */
+struct SessionDestroyedException : public SessionException {
+ SessionDestroyedException(const std::string& msg) : SessionException(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(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(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(m), code(c) {}
+ Code code;
+};
+
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_AMQP_0_10_EXCEPTION_H*/
diff --git a/qpid/cpp/src/qpid/amqp_0_10/Frame.cpp b/qpid/cpp/src/qpid/amqp_0_10/Frame.cpp
new file mode 100644
index 0000000000..1140b6058d
--- /dev/null
+++ b/qpid/cpp/src/qpid/amqp_0_10/Frame.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 "Frame.h"
+
+namespace qpid {
+namespace amqp_0_10 {
+
+bool Frame::match(const Frame& x) {
+}
+}} // namespace qpid::amqp_0_10
diff --git a/qpid/cpp/src/qpid/amqp_0_10/FrameHeader.cpp b/qpid/cpp/src/qpid/amqp_0_10/FrameHeader.cpp
new file mode 100644
index 0000000000..f1a59b9e27
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/amqp_0_10/FrameHeader.h b/qpid/cpp/src/qpid/amqp_0_10/FrameHeader.h
new file mode 100644
index 0000000000..b2f0619f9b
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/amqp_0_10/Header.h b/qpid/cpp/src/qpid/amqp_0_10/Header.h
new file mode 100644
index 0000000000..44edcb9f3d
--- /dev/null
+++ b/qpid/cpp/src/qpid/amqp_0_10/Header.h
@@ -0,0 +1,42 @@
+#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 <ostream>
+
+namespace qpid {
+namespace amqp_0_10 {
+
+// FIXME aconway 2008-03-27: TODO
+class Header
+{
+ public:
+ template <class S> void serialize(S&) {}
+ private:
+};
+
+// FIXME aconway 2008-03-28: TODO
+inline std::ostream& operator<<(std::ostream& o, const Header&) { return o; }
+
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_AMQP_0_10_HEADER_H*/
diff --git a/qpid/cpp/src/qpid/amqp_0_10/Holder.h b/qpid/cpp/src/qpid/amqp_0_10/Holder.h
new file mode 100644
index 0000000000..1664afcc8f
--- /dev/null
+++ b/qpid/cpp/src/qpid/amqp_0_10/Holder.h
@@ -0,0 +1,95 @@
+#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);
+ apply(s, *this->get());
+ }
+
+ 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);
+ apply(assign, rhs);
+ return *this;
+}
+
+
+
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_AMQP_0_10_HOLDER_H*/
diff --git a/qpid/cpp/src/qpid/amqp_0_10/Map.cpp b/qpid/cpp/src/qpid/amqp_0_10/Map.cpp
new file mode 100644
index 0000000000..2d32466c3f
--- /dev/null
+++ b/qpid/cpp/src/qpid/amqp_0_10/Map.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 "all_built_in_types.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/qpid/cpp/src/qpid/amqp_0_10/Map.h b/qpid/cpp/src/qpid/amqp_0_10/Map.h
new file mode 100644
index 0000000000..d63eb0cc4e
--- /dev/null
+++ b/qpid/cpp/src/qpid/amqp_0_10/Map.h
@@ -0,0 +1,184 @@
+#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:
+ static const size_t SIZE=128 < sizeof(Vbin32) ? sizeof(Vbin32) : 128;
+ 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.getLimit() > 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/qpid/cpp/src/qpid/amqp_0_10/Packer.h b/qpid/cpp/src/qpid/amqp_0_10/Packer.h
new file mode 100644
index 0000000000..90d72408b5
--- /dev/null
+++ b/qpid/cpp/src/qpid/amqp_0_10/Packer.h
@@ -0,0 +1,165 @@
+#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 PackBytes> struct PackBitsType;
+template <> struct PackBitsType<1> { typedef uint8_t type; };
+template <> struct PackBitsType<2> { typedef uint16_t type; };
+template <> struct PackBitsType<4> { typedef uint32_t type; };
+
+/**
+ * Helper to serialize packed structs.
+ */
+template <class T> class Packer
+{
+ public:
+ typedef typename PackBitsType<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);
+ }
+
+
+ private:
+ T& data;
+};
+
+}} // namespace qpid::amqp_0_10
+
+
+
+#endif /*!QPID_PACKER_H*/
diff --git a/qpid/cpp/src/qpid/amqp_0_10/SerializableString.h b/qpid/cpp/src/qpid/amqp_0_10/SerializableString.h
new file mode 100644
index 0000000000..485b7ca6a8
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/amqp_0_10/Unit.cpp b/qpid/cpp/src/qpid/amqp_0_10/Unit.cpp
new file mode 100644
index 0000000000..1fa6b2e085
--- /dev/null
+++ b/qpid/cpp/src/qpid/amqp_0_10/Unit.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 "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();
+ case HEADER: variant=Header();
+ case BODY: variant=Body(header.getDataSize());
+ }
+}
+
+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/qpid/cpp/src/qpid/amqp_0_10/Unit.h b/qpid/cpp/src/qpid/amqp_0_10/Unit.h
new file mode 100644
index 0000000000..0229e07419
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/amqp_0_10/UnitHandler.h b/qpid/cpp/src/qpid/amqp_0_10/UnitHandler.h
new file mode 100644
index 0000000000..93a8ce573a
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/amqp_0_10/UnknownType.cpp b/qpid/cpp/src/qpid/amqp_0_10/UnknownType.cpp
new file mode 100644
index 0000000000..844891d732
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/amqp_0_10/UnknownType.h b/qpid/cpp/src/qpid/amqp_0_10/UnknownType.h
new file mode 100644
index 0000000000..1e4aa04bf4
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/amqp_0_10/all_built_in_types.h b/qpid/cpp/src/qpid/amqp_0_10/all_built_in_types.h
new file mode 100644
index 0000000000..1568465004
--- /dev/null
+++ b/qpid/cpp/src/qpid/amqp_0_10/all_built_in_types.h
@@ -0,0 +1,31 @@
+#ifndef QPID_AMQP_0_10_ALL_BUILT_IN_TYPES_H
+#define QPID_AMQP_0_10_ALL_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 "built_in_types.h"
+#include "Map.h"
+#include "Array.h"
+#include "UnknownType.h"
+#include "complex_types.h"
+
+#endif /*!QPID_AMQP_0_10_ALL_BUILT_IN_TYPES_H*/
diff --git a/qpid/cpp/src/qpid/amqp_0_10/apply.h b/qpid/cpp/src/qpid/amqp_0_10/apply.h
new file mode 100644
index 0000000000..f32b3482ef
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/amqp_0_10/built_in_types.h b/qpid/cpp/src/qpid/amqp_0_10/built_in_types.h
new file mode 100644
index 0000000000..dccb6a4785
--- /dev/null
+++ b/qpid/cpp/src/qpid/amqp_0_10/built_in_types.h
@@ -0,0 +1,165 @@
+#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/SequenceNumber.h"
+#include "qpid/framing/Uuid.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>
+#include <stdint.h>
+
+/**@file Mapping from built-in AMQP types to C++ types */
+
+namespace qpid {
+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;
+
+// Forward declare class types.
+class Map;
+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 SequenceSet { template <class S> void serialize(S&) {} };
+struct List { template <class S> void serialize(S&) {} };
+struct Struct32 { 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; }
+inline std::ostream& operator<<(std::ostream& o, const Struct32&) { 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/qpid/cpp/src/qpid/amqp_0_10/complex_types.cpp b/qpid/cpp/src/qpid/amqp_0_10/complex_types.cpp
new file mode 100644
index 0000000000..78ddfeb026
--- /dev/null
+++ b/qpid/cpp/src/qpid/amqp_0_10/complex_types.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/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); }
+
+
+uint8_t Struct::getCode() const { return apply(GetCode(), *this); }
+uint8_t Struct::getPack() const { return apply(GetPack(), *this); }
+uint8_t Struct::getSize() const { return apply(GetSize(), *this); }
+uint8_t Struct::getClassCode() const { return apply(GetClassCode(), *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/qpid/cpp/src/qpid/amqp_0_10/complex_types.h b/qpid/cpp/src/qpid/amqp_0_10/complex_types.h
new file mode 100644
index 0000000000..5d327cc46e
--- /dev/null
+++ b/qpid/cpp/src/qpid/amqp_0_10/complex_types.h
@@ -0,0 +1,113 @@
+#ifndef QPID_AMQP_0_10_COMPLEX_TYPES_H
+#define QPID_AMQP_0_10_COMPLEX_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 "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;
+};
+
+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 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;
+};
+std::ostream& operator<<(std::ostream&, const Command&);
+
+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&);
+
+// 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&);
+
+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_COMPLEX_TYPES_H*/
diff --git a/qpid/cpp/src/qpid/assert.cpp b/qpid/cpp/src/qpid/assert.cpp
new file mode 100644
index 0000000000..5d039da528
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/assert.h b/qpid/cpp/src/qpid/assert.h
new file mode 100644
index 0000000000..49e7c5355d
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/broker/Bridge.cpp b/qpid/cpp/src/qpid/broker/Bridge.cpp
new file mode 100644
index 0000000000..32819380de
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/Bridge.cpp
@@ -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 "Bridge.h"
+#include "ConnectionState.h"
+
+#include "qpid/management/ManagementAgent.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/Uuid.h"
+
+using qpid::framing::FieldTable;
+using qpid::framing::Uuid;
+
+namespace qpid {
+namespace broker {
+
+Bridge::Bridge(framing::ChannelId id, ConnectionState& c, CancellationListener l, const management::ArgsLinkBridge& _args) :
+ args(_args), channel(id, &(c.getOutput())), peer(channel),
+ mgmtObject(new management::Bridge(this, &c, id, args.i_src, args.i_dest, args.i_key, args.i_src_is_queue, args.i_src_is_local)),
+ connection(c), listener(l)
+{
+ management::ManagementAgent::getAgent()->addObject(mgmtObject);
+}
+
+Bridge::~Bridge()
+{
+ mgmtObject->resourceDestroy();
+}
+
+void Bridge::create()
+{
+ framing::AMQP_ServerProxy::Session session(channel);
+ session.open(0);
+
+ if (args.i_src_is_local) {
+ //TODO: handle 'push' here... simplest way is to create frames and pass them to Connection::received()
+ } else {
+ if (args.i_src_is_queue) {
+ peer.getMessage().subscribe(0, args.i_src, args.i_dest, false, 0, 0, false, FieldTable());
+ peer.getMessage().flow(args.i_dest, 0, 0xFFFFFFFF);
+ peer.getMessage().flow(args.i_dest, 1, 0xFFFFFFFF);
+ } else {
+ string queue = "bridge_queue_";
+ queue += Uuid(true).str();
+ peer.getQueue().declare(0, queue, "", false, false, true, true, FieldTable());
+ peer.getQueue().bind(0, queue, args.i_src, args.i_key, FieldTable());
+ peer.getMessage().subscribe(0, queue, args.i_dest, false, 0, 0, false, FieldTable());
+ peer.getMessage().flow(args.i_dest, 0, 0xFFFFFFFF);
+ peer.getMessage().flow(args.i_dest, 1, 0xFFFFFFFF);
+ }
+ }
+
+}
+
+void Bridge::cancel()
+{
+ peer.getMessage().cancel(args.i_dest);
+ peer.getSession().close();
+}
+
+management::ManagementObject::shared_ptr Bridge::GetManagementObject (void) const
+{
+ return dynamic_pointer_cast<management::ManagementObject>(mgmtObject);
+}
+
+management::Manageable::status_t Bridge::ManagementMethod(uint32_t methodId, management::Args& /*args*/)
+{
+ if (methodId == management::Bridge::METHOD_CLOSE) {
+ //notify that we are closed
+ listener(this);
+ //request time on the connections io thread
+ connection.getOutput().activateOutput();
+ return management::Manageable::STATUS_OK;
+ } else {
+ return management::Manageable::STATUS_UNKNOWN_METHOD;
+ }
+}
+
+}}
diff --git a/qpid/cpp/src/qpid/broker/Bridge.h b/qpid/cpp/src/qpid/broker/Bridge.h
new file mode 100644
index 0000000000..1198285c93
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/Bridge.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 _Bridge_
+#define _Bridge_
+
+#include "qpid/framing/AMQP_ServerProxy.h"
+#include "qpid/framing/ChannelHandler.h"
+#include "qpid/management/Manageable.h"
+#include "qpid/management/ArgsLinkBridge.h"
+#include "qpid/management/Bridge.h"
+
+#include <boost/function.hpp>
+
+namespace qpid {
+namespace broker {
+
+class ConnectionState;
+
+class Bridge : public management::Manageable
+{
+public:
+ typedef boost::function<void(Bridge*)> CancellationListener;
+
+ Bridge(framing::ChannelId id, ConnectionState& c, CancellationListener l,
+ const management::ArgsLinkBridge& args);
+ ~Bridge();
+
+ void create();
+ void cancel();
+
+ management::ManagementObject::shared_ptr GetManagementObject() const;
+ management::Manageable::status_t ManagementMethod(uint32_t methodId, management::Args& args);
+
+private:
+ management::ArgsLinkBridge args;
+ framing::ChannelHandler channel;
+ framing::AMQP_ServerProxy peer;
+ management::Bridge::shared_ptr mgmtObject;
+ ConnectionState& connection;
+ CancellationListener listener;
+};
+
+
+}}
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/Broker.cpp b/qpid/cpp/src/qpid/broker/Broker.cpp
new file mode 100644
index 0000000000..b9268db9e5
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/Broker.cpp
@@ -0,0 +1,345 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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 "Broker.h"
+#include "Connection.h"
+#include "DirectExchange.h"
+#include "FanOutExchange.h"
+#include "HeadersExchange.h"
+#include "MessageStoreModule.h"
+#include "NullMessageStore.h"
+#include "RecoveryManagerImpl.h"
+#include "TopicExchange.h"
+#include "qpid/management/PackageQpid.h"
+#include "qpid/management/ManagementExchange.h"
+#include "qpid/management/ArgsBrokerEcho.h"
+
+#include "qpid/log/Statement.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/ProtocolInitiation.h"
+#include "qpid/sys/Acceptor.h"
+#include "qpid/sys/ConnectionInputHandler.h"
+#include "qpid/sys/ConnectionInputHandlerFactory.h"
+#include "qpid/sys/TimeoutHandler.h"
+#include "qpid/sys/SystemInfo.h"
+#include "qpid/Url.h"
+
+#include <boost/bind.hpp>
+
+#include <iostream>
+#include <memory>
+
+#if HAVE_SASL
+#include <sasl/sasl.h>
+#endif
+
+using qpid::sys::Acceptor;
+using qpid::framing::FrameHandler;
+using qpid::framing::ChannelId;
+using qpid::management::ManagementAgent;
+using qpid::management::ManagementObject;
+using qpid::management::Manageable;
+using qpid::management::Args;
+using qpid::management::ArgsBrokerEcho;
+
+namespace qpid {
+namespace broker {
+
+Broker::Options::Options(const std::string& name) :
+ qpid::Options(name),
+ noDataDir(0),
+ dataDir("/var/lib/qpidd"),
+ port(DEFAULT_PORT),
+ workerThreads(5),
+ maxConnections(500),
+ connectionBacklog(10),
+ stagingThreshold(5000000),
+ enableMgmt(1),
+ mgmtPubInterval(10),
+#if HAVE_SASL
+ //Authentication disabled by default for now to allow any
+ //scripts etc that might fail authentication to be updated.
+ //Note that this is a temporary measure (GS 14-APR-2008).
+ auth(false),
+ //auth(true),
+#else
+ auth(false),
+#endif
+ ack(0)
+{
+ int c = sys::SystemInfo::concurrency();
+ workerThreads=c+1;
+ 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")
+ ("auth", optValue(auth, "yes|no"),
+ "Enable authentication, if disabled all incoming connections will be trusted")
+ ("ack", optValue(ack, "N"),
+ "Send session.ack/solicit-ack at least every N frames. 0 disables voluntary ack/solitict-ack");
+}
+
+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) :
+ config(conf),
+ store(0),
+ dataDir(conf.noDataDir ? std::string () : conf.dataDir),
+ factory(*this),
+ sessionManager(conf.ack),
+ previewSessionManager(conf.ack)
+{
+ if(conf.enableMgmt){
+ QPID_LOG(info, "Management enabled");
+ ManagementAgent::enableManagement (dataDir.isEnabled () ? dataDir.getPath () : string (),
+ conf.mgmtPubInterval);
+ managementAgent = ManagementAgent::getAgent ();
+ managementAgent->setInterval (conf.mgmtPubInterval);
+ qpid::management::PackageQpid packageInitializer (managementAgent);
+
+ System* system = new System ();
+ systemObject = System::shared_ptr (system);
+
+ mgmtObject = management::Broker::shared_ptr (new management::Broker (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 (PACKAGE_VERSION);
+ mgmtObject->set_dataDirEnabled (dataDir.isEnabled ());
+ mgmtObject->set_dataDir (dataDir.getPath ());
+
+ managementAgent->addObject (mgmtObject, 1, 0);
+
+ // 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);
+
+ queues.setParent (vhost);
+ exchanges.setParent (vhost);
+ }
+
+ // 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 == 0)
+ setStore (new NullMessageStore (false));
+
+ queues.setStore (store);
+ dtxManager.setStore (store);
+
+ exchanges.declare(empty, DirectExchange::typeName); // Default exchange.
+
+ if (store != 0) {
+ RecoveryManagerImpl recoverer(queues, exchanges, 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);
+ managementAgent->setExchange (mExchange, dExchange);
+ dynamic_pointer_cast<ManagementExchange>(mExchange)->setManagmentAgent (managementAgent);
+ }
+ else
+ QPID_LOG(info, "Management not enabled");
+
+ /**
+ * SASL setup, can fail and terminate startup
+ */
+ if (conf.auth) {
+#if HAVE_SASL
+ int code = sasl_server_init(NULL, BROKER_SASL_NAME);
+ 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));
+ }
+ QPID_LOG(info, "SASL enabled");
+#else
+ throw Exception("Requested authentication but SASL unavailable");
+#endif
+ }
+
+ // Initialize plugins
+ for (Plugin::Plugins::const_iterator i = plugins.begin();
+ i != plugins.end();
+ i++)
+ (*i)->initialize(*this);
+}
+
+void Broker::declareStandardExchange(const std::string& name, const std::string& type)
+{
+ bool storeEnabled = store != NULL;
+ std::pair<Exchange::shared_ptr, bool> status = exchanges.declare(name, type, storeEnabled);
+ if (status.second && storeEnabled) {
+ store->create(*status.first, framing::FieldTable ());
+ }
+}
+
+
+shared_ptr<Broker> Broker::create(int16_t port)
+{
+ Options config;
+ config.port=port;
+ return create(config);
+}
+
+shared_ptr<Broker> Broker::create(const Options& opts)
+{
+ return shared_ptr<Broker>(new Broker(opts));
+}
+
+void Broker::setStore (MessageStore* _store)
+{
+ assert (store == 0 && _store != 0);
+ if (store == 0 && _store != 0)
+ store = new MessageStoreModule (_store);
+}
+
+void Broker::run() {
+ getAcceptor().run(&factory);
+}
+
+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.
+ if (acceptor)
+ acceptor->shutdown();
+}
+
+Broker::~Broker() {
+ shutdown();
+ ManagementAgent::shutdown ();
+ delete store;
+ if (config.auth) {
+#if HAVE_SASL
+ sasl_done();
+#endif
+ }
+}
+
+uint16_t Broker::getPort() const { return getAcceptor().getPort(); }
+
+Acceptor& Broker::getAcceptor() const {
+ if (!acceptor) {
+ const_cast<Acceptor::shared_ptr&>(acceptor) =
+ Acceptor::create(config.port,
+ config.connectionBacklog,
+ config.workerThreads);
+ QPID_LOG(info, "Listening on port " << getPort());
+ }
+ return *acceptor;
+}
+
+ManagementObject::shared_ptr Broker::GetManagementObject(void) const
+{
+ return dynamic_pointer_cast<ManagementObject> (mgmtObject);
+}
+
+Manageable* Broker::GetVhostObject(void) const
+{
+ return vhostObject.get();
+}
+
+Manageable::status_t Broker::ManagementMethod (uint32_t methodId,
+ Args& args)
+{
+ Manageable::status_t status = Manageable::STATUS_UNKNOWN_METHOD;
+
+ QPID_LOG (debug, "Broker::ManagementMethod [id=" << methodId << "]");
+
+ switch (methodId)
+ {
+ case management::Broker::METHOD_ECHO :
+ status = Manageable::STATUS_OK;
+ break;
+ case management::Broker::METHOD_CONNECT : {
+ management::ArgsBrokerConnect& hp=
+ dynamic_cast<management::ArgsBrokerConnect&>(args);
+ connect(hp.i_host, hp.i_port);
+ status = Manageable::STATUS_OK;
+ break;
+ }
+ case management::Broker::METHOD_JOINCLUSTER :
+ case management::Broker::METHOD_LEAVECLUSTER :
+ status = Manageable::STATUS_NOT_IMPLEMENTED;
+ break;
+ }
+
+ return status;
+}
+
+void Broker::connect(
+ const std::string& host, uint16_t port,
+ sys::ConnectionCodec::Factory* f)
+{
+ getAcceptor().connect(host, port, f ? f : &factory);
+}
+
+void Broker::connect(
+ const Url& url, sys::ConnectionCodec::Factory* f)
+{
+ url.throwIfEmpty();
+ TcpAddress addr=boost::get<TcpAddress>(url[0]);
+ connect(addr.host, addr.port, f);
+}
+
+}} // namespace qpid::broker
+
diff --git a/qpid/cpp/src/qpid/broker/Broker.h b/qpid/cpp/src/qpid/broker/Broker.h
new file mode 100644
index 0000000000..8d39c6005d
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/Broker.h
@@ -0,0 +1,157 @@
+#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 "config.h"
+
+#include "ConnectionFactory.h"
+#include "ConnectionToken.h"
+#include "DirectExchange.h"
+#include "DtxManager.h"
+#include "ExchangeRegistry.h"
+#include "MessageStore.h"
+#include "QueueRegistry.h"
+#include "SessionManager.h"
+#include "PreviewSessionManager.h"
+#include "Vhost.h"
+#include "System.h"
+#include "qpid/management/Manageable.h"
+#include "qpid/management/ManagementAgent.h"
+#include "qpid/management/Broker.h"
+#include "qpid/management/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/Acceptor.h"
+#include "qpid/sys/Runnable.h"
+
+#include <vector>
+
+namespace qpid {
+
+class Url;
+
+namespace broker {
+
+static const uint16_t DEFAULT_PORT=5672;
+
+/**
+ * A broker instance.
+ */
+class Broker : public sys::Runnable, public Plugin::Target,
+ public management::Manageable
+{
+ public:
+
+ struct Options : public qpid::Options {
+ 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;
+ bool auth;
+ uint32_t ack;
+ };
+
+ virtual ~Broker();
+
+ Broker(const Options& configuration);
+ static shared_ptr<Broker> create(const Options& configuration);
+ static shared_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;
+
+ /**
+ * 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; }
+ QueueRegistry& getQueues() { return queues; }
+ ExchangeRegistry& getExchanges() { return exchanges; }
+ uint64_t getStagingThreshold() { return config.stagingThreshold; }
+ DtxManager& getDtxManager() { return dtxManager; }
+ DataDir& getDataDir() { return dataDir; }
+ Options& getOptions() { return config; }
+
+ SessionManager& getSessionManager() { return sessionManager; }
+ PreviewSessionManager& getPreviewSessionManager() { return previewSessionManager; }
+
+ management::ManagementObject::shared_ptr GetManagementObject (void) const;
+ management::Manageable* GetVhostObject (void) const;
+ management::Manageable::status_t
+ ManagementMethod (uint32_t methodId, management::Args& args);
+
+ /** Create a connection to another broker. */
+ void connect(const std::string& host, uint16_t port,
+ sys::ConnectionCodec::Factory* =0);
+ /** Create a connection to another broker. */
+ void connect(const Url& url, sys::ConnectionCodec::Factory* =0);
+
+ private:
+ sys::Acceptor& getAcceptor() const;
+
+ Options config;
+ sys::Acceptor::shared_ptr acceptor;
+ MessageStore* store;
+ DataDir dataDir;
+
+ QueueRegistry queues;
+ ExchangeRegistry exchanges;
+ ConnectionFactory factory;
+ DtxManager dtxManager;
+ SessionManager sessionManager;
+ PreviewSessionManager previewSessionManager;
+ management::ManagementAgent::shared_ptr managementAgent;
+ management::Broker::shared_ptr mgmtObject;
+ Vhost::shared_ptr vhostObject;
+ System::shared_ptr systemObject;
+
+ void declareStandardExchange(const std::string& name, const std::string& type);
+};
+
+}}
+
+
+
+#endif /*!_Broker_*/
diff --git a/qpid/cpp/src/qpid/broker/BrokerAdapter.cpp b/qpid/cpp/src/qpid/broker/BrokerAdapter.cpp
new file mode 100644
index 0000000000..ea964ef3a3
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/BrokerAdapter.cpp
@@ -0,0 +1,353 @@
+/*
+ *
+ * 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 "BrokerAdapter.h"
+#include "Connection.h"
+#include "DeliveryToken.h"
+#include "MessageDelivery.h"
+#include "qpid/framing/AMQMethodBody.h"
+#include "qpid/Exception.h"
+#include "qpid/framing/reply_exceptions.h"
+
+namespace qpid {
+namespace broker {
+
+using namespace qpid;
+using namespace qpid::framing;
+
+typedef std::vector<Queue::shared_ptr> QueueVector;
+
+// TODO aconway 2007-08-31: now that functionality is distributed
+// between different handlers, BrokerAdapter should be dropped.
+// Instead the individual class Handler interfaces can be implemented
+// by the handlers responsible for those classes.
+//
+
+BrokerAdapter::BrokerAdapter(SemanticState& s) :
+ HandlerImpl(s),
+ basicHandler(s),
+ exchangeHandler(s),
+ bindingHandler(s),
+ messageHandler(s),
+ queueHandler(s),
+ txHandler(s),
+ dtxHandler(s)
+{}
+
+
+void BrokerAdapter::ExchangeHandlerImpl::declare(uint16_t /*ticket*/, const string& exchange, const string& type,
+ const string& alternateExchange,
+ bool passive, bool durable, bool /*autoDelete*/, const FieldTable& args){
+ 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);
+ }
+ }catch(UnknownExchangeTypeException& e){
+ throw CommandInvalidException(QPID_MSG("Exchange type not implemented: " << type));
+ }
+ }
+}
+
+void BrokerAdapter::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 BrokerAdapter::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 BrokerAdapter::ExchangeHandlerImpl::delete_(uint16_t /*ticket*/, const string& name, bool /*ifUnused*/){
+ //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);
+}
+
+ExchangeQueryResult BrokerAdapter::ExchangeHandlerImpl::query(u_int16_t /*ticket*/, const string& name)
+{
+ try {
+ Exchange::shared_ptr exchange(getBroker().getExchanges().get(name));
+ return ExchangeQueryResult(exchange->getType(), exchange->isDurable(), false, exchange->getArgs());
+ } catch (const ChannelException& e) {
+ return ExchangeQueryResult("", false, true, FieldTable());
+ }
+}
+
+BindingQueryResult BrokerAdapter::BindingHandlerImpl::query(u_int16_t /*ticket*/,
+ const std::string& exchangeName,
+ const std::string& queueName,
+ const std::string& key,
+ const framing::FieldTable& args)
+{
+ Exchange::shared_ptr exchange;
+ try {
+ exchange = getBroker().getExchanges().get(exchangeName);
+ } catch (const ChannelException&) {}
+
+ Queue::shared_ptr queue;
+ if (!queueName.empty()) {
+ queue = getBroker().getQueues().find(queueName);
+ }
+
+ if (!exchange) {
+ return BindingQueryResult(true, false, false, false, false);
+ } else if (!queueName.empty() && !queue) {
+ return BindingQueryResult(false, true, false, false, false);
+ } else if (exchange->isBound(queue, key.empty() ? 0 : &key, args.count() > 0 ? &args : &args)) {
+ return BindingQueryResult(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 BindingQueryResult(false, false, !queueMatched, !keyMatched, !argsMatched);
+ }
+}
+
+QueueQueryResult BrokerAdapter::QueueHandlerImpl::query(const string& name)
+{
+ Queue::shared_ptr queue = state.getQueue(name);
+ 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());
+}
+
+void BrokerAdapter::QueueHandlerImpl::declare(uint16_t /*ticket*/, const string& name, const string& alternateExchange,
+ bool passive, bool durable, bool exclusive,
+ bool autoDelete, const qpid::framing::FieldTable& arguments){
+
+ Exchange::shared_ptr alternate;
+ if (!alternateExchange.empty()) {
+ alternate = getBroker().getExchanges().get(alternateExchange);
+ }
+ Queue::shared_ptr queue;
+ if (passive && !name.empty()) {
+ queue = state.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 ? &getConnection() : 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) {
+ getConnection().exclusiveQueues.push_back(queue);
+ }
+ } else {
+ if (exclusive && queue->setExclusiveOwner(&getConnection())) {
+ getConnection().exclusiveQueues.push_back(queue);
+ }
+ }
+ }
+ if (exclusive && !queue->isExclusiveOwner(&getConnection()))
+ throw ResourceLockedException(
+ QPID_MSG("Cannot grant exclusive access to queue "
+ << queue->getName()));
+}
+
+void BrokerAdapter::QueueHandlerImpl::bind(uint16_t /*ticket*/, const string& queueName,
+ const string& exchangeName, const string& routingKey,
+ const FieldTable& arguments){
+
+ Queue::shared_ptr queue = state.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);
+ }
+ }
+ }else{
+ throw NotFoundException(
+ "Bind failed. No such exchange: " + exchangeName);
+ }
+}
+
+void
+BrokerAdapter::QueueHandlerImpl::unbind(uint16_t /*ticket*/,
+ const string& queueName,
+ const string& exchangeName,
+ const string& routingKey,
+ const qpid::framing::FieldTable& arguments )
+{
+ Queue::shared_ptr queue = state.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);
+
+ if (exchange->unbind(queue, routingKey, &arguments) && exchange->isDurable() && queue->isDurable()) {
+ getBroker().getStore().unbind(*exchange, *queue, routingKey, arguments);
+ }
+
+}
+
+void BrokerAdapter::QueueHandlerImpl::purge(uint16_t /*ticket*/, const string& queue){
+ state.getQueue(queue)->purge();
+}
+
+void BrokerAdapter::QueueHandlerImpl::delete_(uint16_t /*ticket*/, const string& queue, bool ifUnused, bool ifEmpty){
+ ChannelException error(0, "");
+ Queue::shared_ptr q = state.getQueue(queue);
+ 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 = 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);
+ }
+}
+
+
+
+
+void BrokerAdapter::BasicHandlerImpl::qos(uint32_t prefetchSize, uint16_t prefetchCount, bool /*global*/){
+ //TODO: handle global
+ state.setPrefetchSize(prefetchSize);
+ state.setPrefetchCount(prefetchCount);
+}
+
+void BrokerAdapter::BasicHandlerImpl::consume(uint16_t /*ticket*/,
+ const string& queueName, const string& consumerTag,
+ bool noLocal, bool noAck, bool exclusive,
+ bool nowait, const FieldTable& fields)
+{
+
+ Queue::shared_ptr queue = state.getQueue(queueName);
+ if(!consumerTag.empty() && state.exists(consumerTag)){
+ throw NotAllowedException(QPID_MSG("Consumer tags must be unique"));
+ }
+ string newTag = consumerTag;
+ //need to generate name here, so we have it for the adapter (it is
+ //also version specific behaviour now)
+ if (newTag.empty()) newTag = tagGenerator.generate();
+ DeliveryToken::shared_ptr token(MessageDelivery::getBasicConsumeToken(newTag));
+ state.consume(token, newTag, queue, noLocal, !noAck, true, exclusive, &fields);
+
+ if(!nowait)
+ getProxy().getBasic().consumeOk(newTag);
+}
+
+void BrokerAdapter::BasicHandlerImpl::cancel(const string& consumerTag){
+ state.cancel(consumerTag);
+}
+
+void BrokerAdapter::BasicHandlerImpl::get(uint16_t /*ticket*/, const string& queueName, bool noAck){
+ Queue::shared_ptr queue = state.getQueue(queueName);
+ DeliveryToken::shared_ptr token(MessageDelivery::getBasicGetToken(queue));
+ if(!state.get(token, queue, !noAck)){
+ string clusterId;//not used, part of an imatix hack
+
+ getProxy().getBasic().getEmpty(clusterId);
+ }
+}
+
+void BrokerAdapter::BasicHandlerImpl::ack(uint64_t deliveryTag, bool multiple){
+ if (multiple) {
+ state.ackCumulative(deliveryTag);
+ } else {
+ state.ackRange(deliveryTag, deliveryTag);
+ }
+}
+
+void BrokerAdapter::BasicHandlerImpl::reject(uint64_t /*deliveryTag*/, bool /*requeue*/){}
+
+void BrokerAdapter::BasicHandlerImpl::recover(bool requeue)
+{
+ state.recover(requeue);
+}
+
+void BrokerAdapter::TxHandlerImpl::select()
+{
+ state.startTx();
+}
+
+void BrokerAdapter::TxHandlerImpl::commit()
+{
+ state.commit(&getBroker().getStore(), true);
+}
+
+void BrokerAdapter::TxHandlerImpl::rollback()
+{
+ state.rollback();
+ state.recover(true);
+}
+
+}} // namespace qpid::broker
+
diff --git a/qpid/cpp/src/qpid/broker/BrokerAdapter.h b/qpid/cpp/src/qpid/broker/BrokerAdapter.h
new file mode 100644
index 0000000000..b28c4ebdcc
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/BrokerAdapter.h
@@ -0,0 +1,208 @@
+#ifndef _broker_BrokerAdapter_h
+#define _broker_BrokerAdapter_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 "DtxHandlerImpl.h"
+#include "MessageHandlerImpl.h"
+
+#include "qpid/Exception.h"
+#include "qpid/framing/AMQP_ServerOperations.h"
+#include "qpid/framing/reply_exceptions.h"
+
+namespace qpid {
+namespace broker {
+
+class Channel;
+class Connection;
+class Broker;
+class ConnectionHandler;
+class BasicHandler;
+class ExchangeHandler;
+class QueueHandler;
+class TxHandler;
+class MessageHandler;
+class AccessHandler;
+class FileHandler;
+class StreamHandler;
+class DtxHandler;
+class TunnelHandler;
+class MessageHandlerImpl;
+class Exchange;
+
+/**
+ * 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 BrokerAdapter : public HandlerImpl, public framing::AMQP_ServerOperations
+{
+ public:
+ BrokerAdapter(SemanticState& session);
+
+ BasicHandler* getBasicHandler() { return &basicHandler; }
+ ExchangeHandler* getExchangeHandler() { return &exchangeHandler; }
+ BindingHandler* getBindingHandler() { return &bindingHandler; }
+ QueueHandler* getQueueHandler() { return &queueHandler; }
+ TxHandler* getTxHandler() { return &txHandler; }
+ MessageHandler* getMessageHandler() { return &messageHandler; }
+ DtxCoordinationHandler* getDtxCoordinationHandler() { return &dtxHandler; }
+ DtxDemarcationHandler* getDtxDemarcationHandler() { return &dtxHandler; }
+
+ framing::ProtocolVersion getVersion() const { return session.getConnection().getVersion();}
+
+
+ AccessHandler* getAccessHandler() {
+ throw framing::NotImplementedException("Access class not implemented"); }
+ FileHandler* getFileHandler() {
+ throw framing::NotImplementedException("File class not implemented"); }
+ StreamHandler* getStreamHandler() {
+ throw framing::NotImplementedException("Stream class not implemented"); }
+ TunnelHandler* getTunnelHandler() {
+ throw framing::NotImplementedException("Tunnel class not implemented"); }
+
+ Exchange010Handler* getExchange010Handler() { throw framing::NotImplementedException("Class not implemented"); }
+ Queue010Handler* getQueue010Handler() { throw framing::NotImplementedException("Class not implemented"); }
+ Message010Handler* getMessage010Handler() { throw framing::NotImplementedException("Class not implemented"); }
+ Tx010Handler* getTx010Handler() { throw framing::NotImplementedException("Class not implemented"); }
+ Dtx010Handler* getDtx010Handler() { throw framing::NotImplementedException("Class not implemented"); }
+ Execution010Handler* getExecution010Handler() { throw framing::NotImplementedException("Class not implemented"); }
+
+ // Handlers no longer implemented in BrokerAdapter:
+#define BADHANDLER() assert(0); throw framing::NotImplementedException("")
+ ExecutionHandler* getExecutionHandler() { BADHANDLER(); }
+ ConnectionHandler* getConnectionHandler() { BADHANDLER(); }
+ SessionHandler* getSessionHandler() { BADHANDLER(); }
+ Connection010Handler* getConnection010Handler() { BADHANDLER(); }
+ Session010Handler* getSession010Handler() { BADHANDLER(); }
+#undef BADHANDLER
+
+ private:
+ class ExchangeHandlerImpl :
+ public ExchangeHandler,
+ public HandlerImpl
+ {
+ public:
+ ExchangeHandlerImpl(SemanticState& session) : HandlerImpl(session) {}
+
+ void declare(uint16_t ticket,
+ 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_(uint16_t ticket,
+ const std::string& exchange, bool ifUnused);
+ framing::ExchangeQueryResult query(u_int16_t ticket,
+ const std::string& name);
+ private:
+ void checkType(shared_ptr<Exchange> exchange, const std::string& type);
+
+ void checkAlternate(shared_ptr<Exchange> exchange,
+ shared_ptr<Exchange> alternate);
+ };
+
+ class BindingHandlerImpl :
+ public BindingHandler,
+ public HandlerImpl
+ {
+ public:
+ BindingHandlerImpl(SemanticState& session) : HandlerImpl(session) {}
+
+ framing::BindingQueryResult query(u_int16_t ticket,
+ const std::string& exchange,
+ const std::string& queue,
+ const std::string& routingKey,
+ const framing::FieldTable& arguments);
+ };
+
+ class QueueHandlerImpl :
+ public QueueHandler,
+ public HandlerImpl
+ {
+ public:
+ QueueHandlerImpl(SemanticState& session) : HandlerImpl(session) {}
+
+ void declare(uint16_t ticket, const std::string& queue,
+ const std::string& alternateExchange,
+ bool passive, bool durable, bool exclusive,
+ bool autoDelete,
+ const qpid::framing::FieldTable& arguments);
+ void bind(uint16_t ticket, const std::string& queue,
+ const std::string& exchange, const std::string& routingKey,
+ const qpid::framing::FieldTable& arguments);
+ void unbind(uint16_t ticket,
+ const std::string& queue,
+ const std::string& exchange,
+ const std::string& routingKey,
+ const qpid::framing::FieldTable& arguments );
+ framing::QueueQueryResult query(const std::string& queue);
+ void purge(uint16_t ticket, const std::string& queue);
+ void delete_(uint16_t ticket, const std::string& queue,
+ bool ifUnused, bool ifEmpty);
+ };
+
+ class BasicHandlerImpl :
+ public BasicHandler,
+ public HandlerImpl
+ {
+ NameGenerator tagGenerator;
+ public:
+ BasicHandlerImpl(SemanticState& session) : HandlerImpl(session), tagGenerator("sgen") {}
+
+ void qos(uint32_t prefetchSize,
+ uint16_t prefetchCount, bool global);
+ void consume(uint16_t ticket, const std::string& queue,
+ const std::string& consumerTag,
+ bool noLocal, bool noAck, bool exclusive, bool nowait,
+ const qpid::framing::FieldTable& fields);
+ void cancel(const std::string& consumerTag);
+ void get(uint16_t ticket, const std::string& queue, bool noAck);
+ void ack(uint64_t deliveryTag, bool multiple);
+ void reject(uint64_t deliveryTag, bool requeue);
+ void recover(bool requeue);
+ };
+
+ class TxHandlerImpl :
+ public TxHandler,
+ public HandlerImpl
+ {
+ public:
+ TxHandlerImpl(SemanticState& session) : HandlerImpl(session) {}
+
+ void select();
+ void commit();
+ void rollback();
+ };
+
+ BasicHandlerImpl basicHandler;
+ ExchangeHandlerImpl exchangeHandler;
+ BindingHandlerImpl bindingHandler;
+ MessageHandlerImpl messageHandler;
+ QueueHandlerImpl queueHandler;
+ TxHandlerImpl txHandler;
+ DtxHandlerImpl dtxHandler;
+};
+}} // namespace qpid::broker
+
+
+
+#endif /*!_broker_BrokerAdapter_h*/
diff --git a/qpid/cpp/src/qpid/broker/BrokerSingleton.cpp b/qpid/cpp/src/qpid/broker/BrokerSingleton.cpp
new file mode 100644
index 0000000000..77200dd760
--- /dev/null
+++ b/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();
+ shared_ptr<Broker>::operator=(broker);
+}
+
+BrokerSingleton::~BrokerSingleton() {
+ broker->shutdown();
+}
+
+shared_ptr<Broker> BrokerSingleton::broker;
+
+}} // namespace qpid::broker
diff --git a/qpid/cpp/src/qpid/broker/BrokerSingleton.h b/qpid/cpp/src/qpid/broker/BrokerSingleton.h
new file mode 100644
index 0000000000..14b932df36
--- /dev/null
+++ b/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 shared_ptr<Broker>
+{
+ public:
+ BrokerSingleton();
+ ~BrokerSingleton();
+ private:
+ static shared_ptr<Broker> broker;
+};
+
+}} // namespace qpid::broker
+
+
+
+#endif /*!_broker_BrokerSingleton_h*/
diff --git a/qpid/cpp/src/qpid/broker/Connection.cpp b/qpid/cpp/src/qpid/broker/Connection.cpp
new file mode 100644
index 0000000000..ef1100a2ec
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/Connection.cpp
@@ -0,0 +1,328 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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 "BrokerAdapter.h"
+#include "Bridge.h"
+#include "SemanticHandler.h"
+
+#include "qpid/log/Statement.h"
+#include "qpid/ptr_map.h"
+#include "qpid/framing/AMQP_ClientProxy.h"
+#include "qpid/management/ManagementAgent.h"
+
+#include <boost/bind.hpp>
+#include <boost/ptr_container/ptr_vector.hpp>
+
+#include <algorithm>
+#include <iostream>
+#include <assert.h>
+
+using namespace boost;
+using namespace qpid::sys;
+using namespace qpid::framing;
+using namespace qpid::sys;
+using namespace qpid::ptr_map;
+using qpid::management::ManagementAgent;
+using qpid::management::ManagementObject;
+using qpid::management::Manageable;
+using qpid::management::Args;
+
+namespace qpid {
+namespace broker {
+
+class Connection::MgmtClient : public Connection::MgmtWrapper
+{
+ management::Client::shared_ptr mgmtClient;
+
+public:
+ MgmtClient(Connection* conn, Manageable* parent, ManagementAgent::shared_ptr agent, const std::string& mgmtId);
+ ~MgmtClient();
+ void received(framing::AMQFrame& frame);
+ management::ManagementObject::shared_ptr getManagementObject() const;
+ void closing();
+};
+
+class Connection::MgmtLink : public Connection::MgmtWrapper
+{
+ typedef boost::ptr_vector<Bridge> Bridges;
+
+ management::Link::shared_ptr mgmtLink;
+ Bridges created;//holds list of bridges pending creation
+ Bridges cancelled;//holds list of bridges pending cancellation
+ Bridges active;//holds active bridges
+ uint channelCounter;
+ sys::Mutex linkLock;
+
+ void cancel(Bridge*);
+
+public:
+ MgmtLink(Connection* conn, Manageable* parent, ManagementAgent::shared_ptr agent, const std::string& mgmtId);
+ ~MgmtLink();
+ void received(framing::AMQFrame& frame);
+ management::ManagementObject::shared_ptr getManagementObject() const;
+ void closing();
+ void processPending();
+ void process(Connection& connection, const management::Args& args);
+};
+
+
+Connection::Connection(ConnectionOutputHandler* out_, Broker& broker_, const std::string& mgmtId_) :
+ ConnectionState(out_, broker_),
+ adapter(*this),
+ mgmtClosing(false),
+ mgmtId(mgmtId_)
+{
+ initMgmt();
+}
+
+void Connection::initMgmt(bool asLink)
+{
+ Manageable* parent = broker.GetVhostObject ();
+
+ if (parent != 0)
+ {
+ ManagementAgent::shared_ptr agent = ManagementAgent::getAgent ();
+
+ if (agent.get () != 0)
+ {
+ if (asLink) {
+ mgmtWrapper = std::auto_ptr<MgmtWrapper>(new MgmtLink(this, parent, agent, mgmtId));
+ } else {
+ mgmtWrapper = std::auto_ptr<MgmtWrapper>(new MgmtClient(this, parent, agent, mgmtId));
+ }
+ }
+ }
+}
+
+Connection::~Connection () {}
+
+void Connection::received(framing::AMQFrame& frame){
+ if (mgmtClosing)
+ close (403, "Closed by Management Request", 0, 0);
+
+ if (frame.getChannel() == 0 && frame.getMethod()) {
+ adapter.handle(frame);
+ } else {
+ getChannel(frame.getChannel()).in(frame);
+ }
+
+ if (mgmtWrapper.get()) mgmtWrapper->received(frame);
+}
+
+void Connection::close(
+ ReplyCode code, const string& text, ClassId classId, MethodId methodId)
+{
+ adapter.close(code, text, classId, methodId);
+ channels.clear();
+ getOutput().close();
+}
+
+void Connection::idleOut(){}
+
+void Connection::idleIn(){}
+
+void Connection::closed(){ // Physically closed, suspend open sessions.
+ try {
+ for (ChannelMap::iterator i = channels.begin(); i != channels.end(); ++i)
+ get_pointer(i)->localSuspend();
+ 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, " Unhandled exception while closing session: " <<
+ e.what());
+ assert(0);
+ }
+}
+
+bool Connection::doOutput()
+{
+ try{
+ //process any pending mgmt commands:
+ if (mgmtWrapper.get()) mgmtWrapper->processPending();
+ if (mgmtClosing) close (403, "Closed by Management Request", 0, 0);
+
+ //then do other output as needed:
+ return outputTasks.doOutput();
+ }catch(ConnectionException& e){
+ close(e.code, e.what(), 0, 0);
+ }catch(std::exception& e){
+ close(541/*internal error*/, e.what(), 0, 0);
+ }
+ 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 *get_pointer(i);
+}
+
+ManagementObject::shared_ptr Connection::GetManagementObject (void) const
+{
+ return mgmtWrapper.get() ? mgmtWrapper->getManagementObject() : ManagementObject::shared_ptr();
+}
+
+Manageable::status_t Connection::ManagementMethod (uint32_t methodId,
+ Args& args)
+{
+ Manageable::status_t status = Manageable::STATUS_UNKNOWN_METHOD;
+
+ QPID_LOG (debug, "Connection::ManagementMethod [id=" << methodId << "]");
+
+ switch (methodId)
+ {
+ case management::Client::METHOD_CLOSE :
+ mgmtClosing = true;
+ if (mgmtWrapper.get()) mgmtWrapper->closing();
+ out->activateOutput();
+ status = Manageable::STATUS_OK;
+ break;
+ case management::Link::METHOD_BRIDGE :
+ //queue this up and request chance to do output (i.e. get connections thread of control):
+ mgmtWrapper->process(*this, args);
+ out->activateOutput();
+ status = Manageable::STATUS_OK;
+ break;
+ }
+
+ return status;
+}
+
+Connection::MgmtLink::MgmtLink(Connection* conn, Manageable* parent, ManagementAgent::shared_ptr agent, const std::string& mgmtId)
+ : channelCounter(1)
+{
+ mgmtLink = management::Link::shared_ptr
+ (new management::Link(conn, parent, mgmtId));
+ agent->addObject (mgmtLink);
+}
+
+Connection::MgmtLink::~MgmtLink()
+{
+ if (mgmtLink.get () != 0)
+ mgmtLink->resourceDestroy ();
+}
+
+void Connection::MgmtLink::received(framing::AMQFrame& frame)
+{
+ if (mgmtLink.get () != 0)
+ {
+ mgmtLink->inc_framesFromPeer ();
+ mgmtLink->inc_bytesFromPeer (frame.size ());
+ }
+}
+
+management::ManagementObject::shared_ptr Connection::MgmtLink::getManagementObject() const
+{
+ return dynamic_pointer_cast<ManagementObject>(mgmtLink);
+}
+
+void Connection::MgmtLink::closing()
+{
+ if (mgmtLink) mgmtLink->set_closing (1);
+}
+
+void Connection::MgmtLink::processPending()
+{
+ Mutex::ScopedLock l(linkLock);
+ //process any pending creates
+ if (!created.empty()) {
+ for (Bridges::iterator i = created.begin(); i != created.end(); ++i) {
+ i->create();
+ }
+ active.transfer(active.end(), created.begin(), created.end(), created);
+ }
+ if (!cancelled.empty()) {
+ //process any pending cancellations
+ for (Bridges::iterator i = cancelled.begin(); i != cancelled.end(); ++i) {
+ i->cancel();
+ }
+ cancelled.clear();
+ }
+}
+
+void Connection::MgmtLink::process(Connection& connection, const management::Args& args)
+{
+ Mutex::ScopedLock l(linkLock);
+ created.push_back(new Bridge(channelCounter++, connection,
+ boost::bind(&MgmtLink::cancel, this, _1),
+ dynamic_cast<const management::ArgsLinkBridge&>(args)));
+}
+
+void Connection::MgmtLink::cancel(Bridge* b)
+{
+ Mutex::ScopedLock l(linkLock);
+ //need to take this out the active map and add it to the cancelled map
+ for (Bridges::iterator i = active.begin(); i != active.end(); i++) {
+ if (&(*i) == b) {
+ cancelled.transfer(cancelled.end(), i, active);
+ break;
+ }
+ }
+}
+
+Connection::MgmtClient::MgmtClient(Connection* conn, Manageable* parent, ManagementAgent::shared_ptr agent, const std::string& mgmtId)
+{
+ mgmtClient = management::Client::shared_ptr
+ (new management::Client (conn, parent, mgmtId));
+ agent->addObject (mgmtClient);
+}
+
+Connection::MgmtClient::~MgmtClient()
+{
+ if (mgmtClient.get () != 0)
+ mgmtClient->resourceDestroy ();
+}
+
+void Connection::MgmtClient::received(framing::AMQFrame& frame)
+{
+ if (mgmtClient.get () != 0)
+ {
+ mgmtClient->inc_framesFromClient ();
+ mgmtClient->inc_bytesFromClient (frame.size ());
+ }
+}
+
+management::ManagementObject::shared_ptr Connection::MgmtClient::getManagementObject() const
+{
+ return dynamic_pointer_cast<ManagementObject>(mgmtClient);
+}
+
+void Connection::MgmtClient::closing()
+{
+ if (mgmtClient) mgmtClient->set_closing (1);
+}
+
+}}
+
diff --git a/qpid/cpp/src/qpid/broker/Connection.h b/qpid/cpp/src/qpid/broker/Connection.h
new file mode 100644
index 0000000000..a59df26c84
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/Connection.h
@@ -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.
+ *
+ */
+#ifndef _Connection_
+#define _Connection_
+
+#include <memory>
+#include <sstream>
+#include <vector>
+
+#include <boost/ptr_container/ptr_map.hpp>
+
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/AMQP_ServerOperations.h"
+#include "qpid/framing/AMQP_ClientProxy.h"
+#include "qpid/sys/AggregateOutput.h"
+#include "qpid/sys/ConnectionOutputHandler.h"
+#include "qpid/sys/ConnectionInputHandler.h"
+#include "qpid/sys/TimeoutHandler.h"
+#include "qpid/framing/ProtocolVersion.h"
+#include "Broker.h"
+#include "qpid/sys/Socket.h"
+#include "qpid/Exception.h"
+#include "ConnectionHandler.h"
+#include "ConnectionState.h"
+#include "SessionHandler.h"
+#include "qpid/management/Manageable.h"
+#include "qpid/management/Client.h"
+#include "qpid/management/Link.h"
+
+#include <boost/ptr_container/ptr_map.hpp>
+
+namespace qpid {
+namespace broker {
+
+class Connection : public sys::ConnectionInputHandler,
+ public ConnectionState
+{
+ public:
+ Connection(sys::ConnectionOutputHandler* out, Broker& broker, const std::string& mgmtId);
+ ~Connection ();
+
+ /** Get the SessionHandler for channel. Create if it does not already exist */
+ SessionHandler& getChannel(framing::ChannelId channel);
+
+ /** Close the connection */
+ void close(framing::ReplyCode code, const string& text, framing::ClassId classId, framing::MethodId methodId);
+
+ // ConnectionInputHandler methods
+ void received(framing::AMQFrame& frame);
+ void idleOut();
+ void idleIn();
+ void closed();
+ bool doOutput();
+
+ void closeChannel(framing::ChannelId channel);
+
+ // Manageable entry points
+ management::ManagementObject::shared_ptr GetManagementObject (void) const;
+ management::Manageable::status_t
+ ManagementMethod (uint32_t methodId, management::Args& args);
+
+ void initMgmt(bool asLink = false);
+
+ private:
+ typedef boost::ptr_map<framing::ChannelId, SessionHandler> ChannelMap;
+ typedef std::vector<Queue::shared_ptr>::iterator queue_iterator;
+
+ /**
+ * Connection may appear, for the purposes of management, as a
+ * normal client initiated connection or as an agent initiated
+ * inter-broker link. This wrapper abstracts the common interface
+ * for both.
+ */
+ class MgmtWrapper
+ {
+ public:
+ virtual ~MgmtWrapper(){}
+ virtual void received(framing::AMQFrame& frame) = 0;
+ virtual management::ManagementObject::shared_ptr getManagementObject() const = 0;
+ virtual void closing() = 0;
+ virtual void processPending(){}
+ virtual void process(Connection&, const management::Args&){}
+ };
+ class MgmtClient;
+ class MgmtLink;
+
+ ChannelMap channels;
+ framing::AMQP_ClientProxy::Connection* client;
+ ConnectionHandler adapter;
+ std::auto_ptr<MgmtWrapper> mgmtWrapper;
+ bool mgmtClosing;
+ const std::string mgmtId;
+};
+
+}}
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/ConnectionFactory.cpp b/qpid/cpp/src/qpid/broker/ConnectionFactory.cpp
new file mode 100644
index 0000000000..cb831f3023
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/ConnectionFactory.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 "ConnectionFactory.h"
+#include "qpid/framing/ProtocolVersion.h"
+#include "qpid/amqp_0_10/Connection.h"
+#include "PreviewConnectionCodec.h"
+
+namespace qpid {
+namespace broker {
+
+using framing::ProtocolVersion;
+
+ConnectionFactory::ConnectionFactory(Broker& b) : broker(b) {}
+
+ConnectionFactory::~ConnectionFactory() {}
+
+sys::ConnectionCodec*
+ConnectionFactory::create(ProtocolVersion v, sys::OutputControl& out, const std::string& id) {
+ if (v == ProtocolVersion(99, 0))
+ return new PreviewConnectionCodec(out, broker, id);
+ if (v == ProtocolVersion(0, 10))
+ return new amqp_0_10::Connection(out, broker, id);
+ return 0;
+}
+
+sys::ConnectionCodec*
+ConnectionFactory::create(sys::OutputControl& out, const std::string& id) {
+ // FIXME aconway 2008-03-18:
+
+ // gsim 2008-03-26 this seems only to be used when creating
+ // connections from one broker to another
+ return new PreviewConnectionCodec(out, broker, id, true);
+}
+
+}} // namespace qpid::broker
diff --git a/qpid/cpp/src/qpid/broker/ConnectionFactory.h b/qpid/cpp/src/qpid/broker/ConnectionFactory.h
new file mode 100644
index 0000000000..5797495054
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/ConnectionFactory.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 _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/qpid/cpp/src/qpid/broker/ConnectionHandler.cpp b/qpid/cpp/src/qpid/broker/ConnectionHandler.cpp
new file mode 100644
index 0000000000..315e03fb2b
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/ConnectionHandler.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 "ConnectionHandler.h"
+#include "Connection.h"
+#include "qpid/framing/ConnectionStartBody.h"
+#include "qpid/framing/Connection010StartBody.h"
+#include "qpid/framing/ClientInvoker.h"
+#include "qpid/framing/ServerInvoker.h"
+
+using namespace qpid;
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+
+namespace
+{
+const std::string PLAIN = "PLAIN";
+const std::string en_US = "en_US";
+}
+
+void ConnectionHandler::close(ReplyCode code, const string& text, ClassId classId, MethodId methodId)
+{
+ handler->client.close(code, text, classId, methodId);
+}
+
+void ConnectionHandler::handle(framing::AMQFrame& frame)
+{
+ AMQMethodBody* method=frame.getBody()->getMethod();
+ try{
+ bool handled = false;
+ if (handler->serverMode) {
+ handled = invoke(static_cast<AMQP_ServerOperations::Connection010Handler&>(*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(), method->amqpClassId(), method->amqpMethodId());
+ }catch(std::exception& e){
+ handler->client.close(541/*internal error*/, e.what(), method->amqpClassId(), method->amqpMethodId());
+ }
+}
+
+ConnectionHandler::ConnectionHandler(Connection& connection) : handler(new Handler(connection)) {
+ FieldTable properties;
+ Array mechanisms(0x95);
+ boost::shared_ptr<FieldValue> m(new Str16Value(PLAIN));
+ mechanisms.add(m);
+ Array locales(0x95);
+ boost::shared_ptr<FieldValue> l(new Str16Value(en_US));
+ locales.add(l);
+ handler->serverMode = true;
+ handler->client.start(properties, mechanisms, locales);
+}
+
+
+
+ConnectionHandler::Handler:: Handler(Connection& c) : client(c.getOutput()), server(c.getOutput()),
+ connection(c), serverMode(false) {}
+
+void ConnectionHandler::Handler::startOk(const framing::FieldTable& /*clientProperties*/,
+ const string& mechanism,
+ const string& response, const string& /*locale*/)
+{
+ //TODO: handle SASL mechanisms more cleverly
+ if (mechanism == PLAIN) {
+ 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);
+ //TODO: authentication
+ connection.setUserId(uid);
+ }
+ }
+ client.tune(framing::CHANNEL_MAX, connection.getFrameMax(), 0, 0);
+}
+
+void ConnectionHandler::Handler::secureOk(const string& /*response*/){}
+
+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*/)
+{
+ framing::Array knownhosts;
+ client.openOk(knownhosts);
+}
+
+
+void ConnectionHandler::Handler::close(uint16_t /*replyCode*/, const string& /*replyText*/,
+ uint16_t /*classId*/, uint16_t /*methodId*/)
+{
+ client.closeOk();
+ connection.getOutput().close();
+}
+
+void ConnectionHandler::Handler::closeOk(){
+ connection.getOutput().close();
+}
+
+
+void ConnectionHandler::Handler::start(uint8_t /*versionMajor*/,
+ uint8_t /*versionMinor*/,
+ const FieldTable& /*serverProperties*/,
+ const string& /*mechanisms*/,
+ const string& /*locales*/)
+{
+ string uid = "qpidd";
+ string pwd = "qpidd";
+ string response = ((char)0) + uid + ((char)0) + pwd;
+ server.startOk(FieldTable(), PLAIN, response, en_US);
+ connection.initMgmt(true);
+}
+
+void ConnectionHandler::Handler::secure(const string& /*challenge*/)
+{
+ server.secureOk("");
+}
+
+void ConnectionHandler::Handler::tune(uint16_t channelMax,
+ uint32_t frameMax,
+ uint16_t heartbeat)
+{
+ connection.setFrameMax(frameMax);
+ connection.setHeartbeat(heartbeat);
+ server.tuneOk(channelMax, frameMax, heartbeat);
+ server.open("/", "", true);
+}
+
+void ConnectionHandler::Handler::openOk(const string& /*knownHosts*/)
+{
+}
+
+void ConnectionHandler::Handler::redirect(const string& /*host*/, const string& /*knownHosts*/)
+{
+
+}
diff --git a/qpid/cpp/src/qpid/broker/ConnectionHandler.h b/qpid/cpp/src/qpid/broker/ConnectionHandler.h
new file mode 100644
index 0000000000..d949d51c43
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/ConnectionHandler.h
@@ -0,0 +1,91 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 "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/FrameHandler.h"
+#include "qpid/framing/ProtocolInitiation.h"
+#include "qpid/framing/ProtocolVersion.h"
+#include "qpid/Exception.h"
+
+namespace qpid {
+namespace broker {
+
+class Connection;
+
+class ConnectionHandler : public framing::FrameHandler
+{
+ struct Handler : public framing::AMQP_ServerOperations::Connection010Handler,
+ public framing::AMQP_ClientOperations::ConnectionHandler
+ {
+ framing::AMQP_ClientProxy::Connection010 client;
+ framing::AMQP_ServerProxy::Connection server;
+ Connection& connection;
+ bool serverMode;
+
+ Handler(Connection& connection);
+ 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,
+ uint16_t classId, uint16_t methodId);
+ void closeOk();
+
+
+ void start(uint8_t versionMajor,
+ uint8_t versionMinor,
+ const qpid::framing::FieldTable& serverProperties,
+ const std::string& mechanisms,
+ const std::string& locales);
+
+ void secure(const std::string& challenge);
+
+ void tune(uint16_t channelMax,
+ uint32_t frameMax,
+ uint16_t heartbeat);
+
+ void openOk(const std::string& knownHosts);
+
+ void redirect(const std::string& host, const std::string& knownHosts);
+ };
+ std::auto_ptr<Handler> handler;
+ public:
+ ConnectionHandler(Connection& connection);
+ void close(framing::ReplyCode code, const std::string& text, framing::ClassId classId, framing::MethodId methodId);
+ void handle(framing::AMQFrame& frame);
+};
+
+
+}}
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/ConnectionState.h b/qpid/cpp/src/qpid/broker/ConnectionState.h
new file mode 100644
index 0000000000..691d47d866
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/ConnectionState.h
@@ -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.
+ *
+ */
+#ifndef _ConnectionState_
+#define _ConnectionState_
+
+#include <vector>
+
+#include "qpid/sys/AggregateOutput.h"
+#include "qpid/sys/ConnectionOutputHandler.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
+{
+ public:
+ ConnectionState(qpid::sys::ConnectionOutputHandler* o, Broker& b) :
+ broker(b),
+ outputTasks(*o),
+ out(o),
+ framemax(65535),
+ heartbeat(0),
+ stagingThreshold(broker.getStagingThreshold())
+ {}
+
+
+
+ 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; }
+
+ void setUserId(const string& uid) { userId = uid; }
+ const string& getUserId() const { return userId; }
+
+ Broker& getBroker() { return broker; }
+
+ Broker& broker;
+ std::vector<Queue::shared_ptr> exclusiveQueues;
+
+ //contained output tasks
+ sys::AggregateOutput outputTasks;
+
+ sys::ConnectionOutputHandler& getOutput() const { return *out; }
+ framing::ProtocolVersion getVersion() const { return version; }
+
+ protected:
+ framing::ProtocolVersion version;
+ sys::ConnectionOutputHandler* out;
+ uint32_t framemax;
+ uint16_t heartbeat;
+ uint64_t stagingThreshold;
+ string userId;
+};
+
+}}
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/ConnectionToken.h b/qpid/cpp/src/qpid/broker/ConnectionToken.h
new file mode 100644
index 0000000000..0e3b301897
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/broker/Consumer.h b/qpid/cpp/src/qpid/broker/Consumer.h
new file mode 100644
index 0000000000..00eb41a428
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/Consumer.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 _Consumer_
+#define _Consumer_
+
+namespace qpid {
+ namespace broker {
+ class Queue;
+}}
+
+#include "Message.h"
+
+namespace qpid {
+ namespace broker {
+
+ struct QueuedMessage
+ {
+ boost::intrusive_ptr<Message> payload;
+ framing::SequenceNumber position;
+ Queue* queue;
+
+ QueuedMessage(Queue* q, boost::intrusive_ptr<Message> msg, framing::SequenceNumber sn) :
+ payload(msg), position(sn), queue(q) {}
+ QueuedMessage(Queue* q) : queue(q) {}
+ };
+
+
+ class Consumer {
+ const bool acquires;
+ public:
+ typedef shared_ptr<Consumer> 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 ~Consumer(){}
+ };
+ }
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/Daemon.cpp b/qpid/cpp/src/qpid/broker/Daemon.cpp
new file mode 100644
index 0000000000..3fcc487324
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/Daemon.cpp
@@ -0,0 +1,192 @@
+/*
+ *
+ * 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 <boost/iostreams/stream.hpp>
+#include <boost/iostreams/device/file_descriptor.hpp>
+
+#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;
+typedef boost::iostreams::stream<boost::iostreams::file_descriptor> fdstream;
+
+namespace {
+/** Throw an exception containing msg and strerror if throwIf is true.
+ * Name is supposed to be reminiscent of perror().
+ */
+void throwIf(bool condition, const string& msg, int errNo=errno) {
+ if (condition)
+ throw Exception(msg + (errNo? ": "+strError(errNo) : string(".")));
+}
+
+
+struct LockFile : public fdstream {
+
+ LockFile(const std::string& path_, bool create)
+ : path(path_), fd(-1), created(create)
+ {
+ errno = 0;
+ int flags=create ? O_WRONLY|O_CREAT|O_NOFOLLOW : O_RDWR;
+ fd = ::open(path.c_str(), flags, 0644);
+ throwIf(fd < 0,"Cannot open "+path);
+ throwIf(::lockf(fd, F_TLOCK, 0) < 0, "Cannot lock "+path);
+ open(boost::iostreams::file_descriptor(fd));
+ }
+
+ ~LockFile() {
+ if (fd >= 0) {
+ ::lockf(fd, F_ULOCK, 0);
+ close();
+ }
+ }
+
+ std::string path;
+ int fd;
+ bool created;
+};
+
+} // namespace
+
+Daemon::Daemon() {
+ pid = -1;
+ pipeFds[0] = pipeFds[1] = -1;
+}
+
+string Daemon::dir() {
+ return (getuid() == 0 ? "/var/run" : "/tmp");
+}
+
+string Daemon::pidFile(uint16_t port) {
+ ostringstream path;
+ path << dir() << "/qpidd." << port << ".pid";
+ return path.str();
+}
+
+void Daemon::fork()
+{
+ throwIf(pipe(pipeFds) < 0, "Can't create pipe");
+ throwIf((pid = ::fork()) < 0, "Daemon fork failed");
+ if (pid == 0) { // Child
+ try {
+ QPID_LOG(debug, "Forked daemon child process");
+
+ // File descriptors
+ throwIf(::close(pipeFds[0])<0, "Cannot close read pipe");
+ throwIf(::close(0)<0, "Cannot close stdin");
+ throwIf(::close(1)<0, "Cannot close stdout");
+ throwIf(::close(2)<0, "Cannot close stderr");
+ int fd=::open("/dev/null",O_RDWR); // stdin
+ throwIf(fd != 0, "Cannot re-open stdin");
+ throwIf(::dup(fd)<0, "Cannot re-open stdout");
+ throwIf(::dup(fd)<0, "Cannot re-open stderror");
+
+ // Misc
+ throwIf(setsid()<0, "Cannot set session ID");
+ throwIf(chdir(dir().c_str()) < 0, "Cannot change directory to "+dir());
+ umask(027);
+
+ // Child behavior
+ child();
+ }
+ catch (const exception& e) {
+ QPID_LOG(critical, "Daemon startup failed: " << e.what());
+ fdstream pipe(pipeFds[1]);
+ assert(pipe.is_open());
+ pipe << "0 " << e.what() << endl;
+ }
+ }
+ 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.
+ 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);
+ throwIf(n==0, "Timed out waiting for daemon");
+ throwIf(n<0, "Error waiting for daemon");
+ fdstream pipe(pipeFds[0]);
+ pipe.exceptions(ios::failbit|ios::badbit|ios::eofbit);
+ uint16_t port = 0;
+ try {
+ pipe >> port;
+ if (port == 0) {
+ string errmsg;
+ pipe >> skipws;
+ getline(pipe, errmsg);
+ throw Exception("Daemon startup failed"+
+ (errmsg.empty() ? string(".") : ": " + errmsg));
+ }
+ }
+ catch (const fdstream::failure& e) {
+ throw Exception(string("Failed to read daemon port: ")+e.what());
+ }
+ return port;
+}
+
+void Daemon::ready(uint16_t port) { // child
+ lockFile = pidFile(port);
+ LockFile lf(lockFile, true);
+ lf << getpid() << endl;
+ if (lf.fail())
+ throw Exception("Cannot write lock file "+lockFile);
+ fdstream pipe(pipeFds[1]);
+ QPID_LOG(debug, "Daemon ready on port: " << port);
+ pipe << port << endl;
+ throwIf(!pipe.good(), "Error writing to parent");
+}
+
+pid_t Daemon::getPid(uint16_t port) {
+ string name = pidFile(port);
+ LockFile lockFile(name, false);
+ pid_t pid;
+ lockFile >> pid;
+ if (lockFile.fail())
+ throw Exception("Cannot read lock file "+name);
+ 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/qpid/cpp/src/qpid/broker/Daemon.h b/qpid/cpp/src/qpid/broker/Daemon.h
new file mode 100644
index 0000000000..821334c11e
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/Daemon.h
@@ -0,0 +1,81 @@
+#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(uint16_t port);
+
+ Daemon();
+
+ 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 dir();
+ static std::string pidFile(uint16_t port);
+
+ pid_t pid;
+ int pipeFds[2];
+ std::string lockFile;
+};
+
+}} // namespace qpid::broker
+
+#endif /*!_broker_Daemon_h*/
diff --git a/qpid/cpp/src/qpid/broker/Deliverable.h b/qpid/cpp/src/qpid/broker/Deliverable.h
new file mode 100644
index 0000000000..e46d2024bf
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/Deliverable.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 _Deliverable_
+#define _Deliverable_
+
+#include "Queue.h"
+
+namespace qpid {
+ namespace broker {
+ class Deliverable{
+ public:
+ bool delivered;
+ Deliverable() : delivered(false) {}
+ virtual void deliverTo(Queue::shared_ptr& queue) = 0;
+ virtual uint64_t contentSize() { return 0; }
+ virtual ~Deliverable(){}
+ };
+ }
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/DeliverableMessage.cpp b/qpid/cpp/src/qpid/broker/DeliverableMessage.cpp
new file mode 100644
index 0000000000..fd15acf464
--- /dev/null
+++ b/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(boost::intrusive_ptr<Message>& _msg) : msg(_msg)
+{
+}
+
+void DeliverableMessage::deliverTo(Queue::shared_ptr& queue)
+{
+ queue->deliver(msg);
+ delivered = true;
+}
+
+Message& DeliverableMessage::getMessage()
+{
+ return *msg;
+}
+
+uint64_t DeliverableMessage::contentSize ()
+{
+ return msg->contentSize ();
+}
diff --git a/qpid/cpp/src/qpid/broker/DeliverableMessage.h b/qpid/cpp/src/qpid/broker/DeliverableMessage.h
new file mode 100644
index 0000000000..18e1ec5e29
--- /dev/null
+++ b/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(boost::intrusive_ptr<Message>& msg);
+ virtual void deliverTo(Queue::shared_ptr& queue);
+ Message& getMessage();
+ uint64_t contentSize();
+ virtual ~DeliverableMessage(){}
+ };
+ }
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/DeliveryAdapter.h b/qpid/cpp/src/qpid/broker/DeliveryAdapter.h
new file mode 100644
index 0000000000..4c2b2f615f
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/DeliveryAdapter.h
@@ -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.
+ *
+ */
+#ifndef _DeliveryAdapter_
+#define _DeliveryAdapter_
+
+#include "DeliveryId.h"
+#include "DeliveryToken.h"
+#include "Message.h"
+#include "qpid/framing/amqp_types.h"
+
+namespace qpid {
+namespace broker {
+
+ /**
+ * 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 DeliveryId deliver(QueuedMessage& msg, DeliveryToken::shared_ptr token) = 0;
+ virtual ~DeliveryAdapter(){}
+ };
+
+}}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/DeliveryId.h b/qpid/cpp/src/qpid/broker/DeliveryId.h
new file mode 100644
index 0000000000..05b19f032e
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/broker/DeliveryRecord.cpp b/qpid/cpp/src/qpid/broker/DeliveryRecord.cpp
new file mode 100644
index 0000000000..4406eccc44
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/DeliveryRecord.cpp
@@ -0,0 +1,211 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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"
+
+using namespace qpid::broker;
+using std::string;
+
+DeliveryRecord::DeliveryRecord(const QueuedMessage& _msg,
+ Queue::shared_ptr _queue,
+ const std::string _tag,
+ DeliveryToken::shared_ptr _token,
+ const DeliveryId _id,
+ bool _acquired, bool accepted) : msg(_msg),
+ queue(_queue),
+ tag(_tag),
+ token(_token),
+ id(_id),
+ acquired(_acquired),
+ pull(false),
+ cancelled(false),
+ credit(msg.payload ? msg.payload->getRequiredCredit() : 0),
+ size(msg.payload ? msg.payload->contentSize() : 0),
+ completed(false),
+ ended(accepted)
+{
+ if (accepted) setEnded();
+}
+
+DeliveryRecord::DeliveryRecord(const QueuedMessage& _msg,
+ Queue::shared_ptr _queue,
+ const DeliveryId _id) : msg(_msg),
+ queue(_queue),
+ id(_id),
+ acquired(true),
+ pull(true),
+ cancelled(false),
+ credit(msg.payload ? msg.payload->getRequiredCredit() : 0),
+ size(msg.payload ? msg.payload->contentSize() : 0),
+ completed(false),
+ ended(false)
+{}
+
+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::AccumulatedAck* const range) const{
+ return range->covers(id);
+}
+
+void DeliveryRecord::redeliver(SemanticState* const session) {
+ if (!ended) {
+ if(pull || cancelled){
+ //if message was originally sent as response to get, we must requeue it
+
+ //or if subscription was cancelled, requeue it (waiting for
+ //final confirmation for AMQP WG on this case)
+
+ requeue();
+ }else{
+ msg.payload->redeliver();//mark as redelivered
+ id = session->redeliver(msg, token);
+ }
+ }
+}
+
+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();
+ }
+}
+
+void DeliveryRecord::complete()
+{
+ completed = true;
+}
+
+void DeliveryRecord::accept(TransactionContext* ctxt) {
+ if (acquired && !ended) {
+ queue->dequeue(ctxt, msg.payload);
+ setEnded();
+ }
+}
+
+void DeliveryRecord::dequeue(TransactionContext* ctxt) const{
+ if (acquired && !ended) {
+ queue->dequeue(ctxt, msg.payload);
+ }
+}
+
+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::addTo(Prefetch& prefetch) const{
+ if(!pull){
+ //ignore 'pulled' messages (i.e. those that were sent in
+ //response to get) when calculating prefetch
+ prefetch.size += size;
+ prefetch.count++;
+ }
+}
+
+void DeliveryRecord::subtractFrom(Prefetch& prefetch) const{
+ if(!pull){
+ //ignore 'pulled' messages (i.e. those that were sent in
+ //response to get) when calculating prefetch
+ prefetch.size -= size;
+ prefetch.count--;
+ }
+}
+
+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;
+}
+
+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/qpid/cpp/src/qpid/broker/DeliveryRecord.h b/qpid/cpp/src/qpid/broker/DeliveryRecord.h
new file mode 100644
index 0000000000..7d08a4b1f0
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/DeliveryRecord.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 _DeliveryRecord_
+#define _DeliveryRecord_
+
+#include <algorithm>
+#include <list>
+#include <vector>
+#include <ostream>
+#include "qpid/framing/AccumulatedAck.h"
+#include "Queue.h"
+#include "Consumer.h"
+#include "DeliveryId.h"
+#include "DeliveryToken.h"
+#include "Message.h"
+#include "Prefetch.h"
+
+namespace qpid {
+namespace broker {
+class SemanticState;
+
+/**
+ * Record of a delivery for which an ack is outstanding.
+ */
+class DeliveryRecord{
+ QueuedMessage msg;
+ mutable Queue::shared_ptr queue;
+ const std::string tag;
+ DeliveryToken::shared_ptr token;
+ DeliveryId id;
+ bool acquired;
+ const bool pull;
+ bool cancelled;
+ const uint32_t credit;
+ const uint64_t size;
+
+ bool completed;
+ bool ended;
+
+ public:
+ DeliveryRecord(const QueuedMessage& msg, Queue::shared_ptr queue, const std::string tag, DeliveryToken::shared_ptr token,
+ const DeliveryId id, bool acquired, bool confirmed = false);
+ DeliveryRecord(const QueuedMessage& msg, Queue::shared_ptr queue, const DeliveryId id);
+
+ bool matches(DeliveryId tag) const;
+ bool matchOrAfter(DeliveryId tag) const;
+ bool after(DeliveryId tag) const;
+ bool coveredBy(const framing::AccumulatedAck* 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();
+
+ bool isAcquired() const { return acquired; }
+ bool isComplete() const { return completed; }
+ bool isRedundant() const { return ended && completed; }
+
+ uint32_t getCredit() const;
+ void addTo(Prefetch&) const;
+ void subtractFrom(Prefetch&) const;
+ const std::string& getTag() const { return tag; }
+ bool isPull() const { return pull; }
+ friend bool operator<(const DeliveryRecord&, const DeliveryRecord&);
+ friend std::ostream& operator<<(std::ostream&, const 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) {}
+};
+
+struct AcquireFunctor
+{
+ DeliveryIds& results;
+
+ AcquireFunctor(DeliveryIds& _results) : results(_results) {}
+
+ void operator()(DeliveryRecord& record)
+ {
+ record.acquire(results);
+ }
+};
+
+}
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/DeliveryToken.h b/qpid/cpp/src/qpid/broker/DeliveryToken.h
new file mode 100644
index 0000000000..8bdf5e6359
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/DeliveryToken.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 _DeliveryToken_
+#define _DeliveryToken_
+
+#include <boost/shared_ptr.hpp>
+
+namespace qpid {
+namespace broker {
+
+ /**
+ * A DeliveryToken allows the delivery of a message to be
+ * associated with whatever mechanism caused it to be
+ * delivered. (i.e. its a form of Memento).
+ */
+ class DeliveryToken
+ {
+ public:
+ typedef boost::shared_ptr<DeliveryToken> shared_ptr;
+
+ virtual ~DeliveryToken(){}
+ };
+
+}}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/DirectExchange.cpp b/qpid/cpp/src/qpid/broker/DirectExchange.cpp
new file mode 100644
index 0000000000..72021b8d98
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/DirectExchange.cpp
@@ -0,0 +1,153 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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;
+
+DirectExchange::DirectExchange(const string& _name, Manageable* _parent) : Exchange(_name, _parent)
+{
+ if (mgmtExchange.get() != 0)
+ mgmtExchange->set_type (typeName);
+}
+
+DirectExchange::DirectExchange(const std::string& _name, bool _durable,
+ const FieldTable& _args, Manageable* _parent) :
+ Exchange(_name, _durable, _args, _parent)
+{
+ if (mgmtExchange.get() != 0)
+ mgmtExchange->set_type (typeName);
+}
+
+bool DirectExchange::bind(Queue::shared_ptr queue, const string& routingKey, const FieldTable*){
+ RWlock::ScopedWlock l(lock);
+ std::vector<Binding::shared_ptr>& queues(bindings[routingKey]);
+ std::vector<Binding::shared_ptr>::iterator i;
+
+ for (i = queues.begin(); i != queues.end(); i++)
+ if ((*i)->queue == queue)
+ break;
+
+ if (i == queues.end()) {
+ Binding::shared_ptr binding (new Binding (routingKey, queue, this));
+ bindings[routingKey].push_back(binding);
+ if (mgmtExchange.get() != 0) {
+ mgmtExchange->inc_bindings();
+ dynamic_pointer_cast<management::Queue>(queue->GetManagementObject())->inc_bindings();
+ }
+ return true;
+ } else{
+ return false;
+ }
+}
+
+bool DirectExchange::unbind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* /*args*/){
+ RWlock::ScopedWlock l(lock);
+ std::vector<Binding::shared_ptr>& queues(bindings[routingKey]);
+ std::vector<Binding::shared_ptr>::iterator i;
+
+ for (i = queues.begin(); i != queues.end(); i++)
+ if ((*i)->queue == queue)
+ break;
+
+ if (i < queues.end()) {
+ queues.erase(i);
+ if (queues.empty()) {
+ bindings.erase(routingKey);
+ }
+ if (mgmtExchange.get() != 0) {
+ mgmtExchange->dec_bindings ();
+ dynamic_pointer_cast<management::Queue>(queue->GetManagementObject())->dec_bindings();
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void DirectExchange::route(Deliverable& msg, const string& routingKey, const FieldTable* /*args*/){
+ RWlock::ScopedRlock l(lock);
+ std::vector<Binding::shared_ptr>& queues(bindings[routingKey]);
+ std::vector<Binding::shared_ptr>::iterator i;
+ int count(0);
+
+ for(i = queues.begin(); i != queues.end(); i++, count++) {
+ msg.deliverTo((*i)->queue);
+ if ((*i)->mgmtBinding.get() != 0)
+ (*i)->mgmtBinding->inc_msgMatched ();
+ }
+
+ if(!count){
+ QPID_LOG(warning, "DirectExchange " << getName() << " could not route message with key " << routingKey);
+ if (mgmtExchange.get() != 0) {
+ mgmtExchange->inc_msgDrops ();
+ mgmtExchange->inc_byteDrops (msg.contentSize ());
+ }
+ }
+ else {
+ if (mgmtExchange.get() != 0) {
+ mgmtExchange->inc_msgRoutes (count);
+ mgmtExchange->inc_byteRoutes (count * msg.contentSize ());
+ }
+ }
+
+ if (mgmtExchange.get() != 0) {
+ mgmtExchange->inc_msgReceives ();
+ mgmtExchange->inc_byteReceives (msg.contentSize ());
+ }
+}
+
+
+bool DirectExchange::isBound(Queue::shared_ptr queue, const string* const routingKey, const FieldTable* const)
+{
+ std::vector<Binding::shared_ptr>::iterator j;
+
+ if (routingKey) {
+ Bindings::iterator i = bindings.find(*routingKey);
+
+ if (i == bindings.end())
+ return false;
+ if (!queue)
+ return true;
+ for (j = i->second.begin(); j != i->second.end(); j++)
+ if ((*j)->queue == queue)
+ return true;
+ } 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++)
+ for (j = i->second.begin(); j != i->second.end(); j++)
+ if ((*j)->queue == queue)
+ return true;
+ return false;
+ }
+
+ return false;
+}
+
+DirectExchange::~DirectExchange() {}
+
+const std::string DirectExchange::typeName("direct");
diff --git a/qpid/cpp/src/qpid/broker/DirectExchange.h b/qpid/cpp/src/qpid/broker/DirectExchange.h
new file mode 100644
index 0000000000..118f2ed4d3
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/DirectExchange.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 _DirectExchange_
+#define _DirectExchange_
+
+#include <map>
+#include <vector>
+#include "Exchange.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/sys/Monitor.h"
+#include "Queue.h"
+
+namespace qpid {
+namespace broker {
+ class DirectExchange : public virtual Exchange{
+ typedef std::vector<Binding::shared_ptr> Queues;
+ typedef std::map<string, Queues> Bindings;
+ Bindings bindings;
+ qpid::sys::RWlock 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();
+ };
+}
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/DtxAck.cpp b/qpid/cpp/src/qpid/broker/DtxAck.cpp
new file mode 100644
index 0000000000..0e6f94d4e0
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/DtxAck.cpp
@@ -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 "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 framing::AccumulatedAck& 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()
+{
+ pending.clear();
+}
+
+void DtxAck::rollback() throw()
+{
+ for_each(pending.begin(), pending.end(), mem_fun_ref(&DeliveryRecord::requeue));
+ pending.clear();
+}
diff --git a/qpid/cpp/src/qpid/broker/DtxAck.h b/qpid/cpp/src/qpid/broker/DtxAck.h
new file mode 100644
index 0000000000..c61b279c42
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/DtxAck.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 _DtxAck_
+#define _DtxAck_
+
+#include <algorithm>
+#include <functional>
+#include <list>
+#include "qpid/framing/AccumulatedAck.h"
+#include "DeliveryRecord.h"
+#include "TxOp.h"
+
+namespace qpid {
+ namespace broker {
+ class DtxAck : public TxOp{
+ std::list<DeliveryRecord> pending;
+
+ public:
+ DtxAck(const framing::AccumulatedAck& acked, std::list<DeliveryRecord>& unacked);
+ virtual bool prepare(TransactionContext* ctxt) throw();
+ virtual void commit() throw();
+ virtual void rollback() throw();
+ virtual ~DtxAck(){}
+ };
+ }
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/DtxBuffer.cpp b/qpid/cpp/src/qpid/broker/DtxBuffer.cpp
new file mode 100644
index 0000000000..29a07ea6d9
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/broker/DtxBuffer.h b/qpid/cpp/src/qpid/broker/DtxBuffer.h
new file mode 100644
index 0000000000..b302632037
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/broker/DtxHandlerImpl.cpp b/qpid/cpp/src/qpid/broker/DtxHandlerImpl.cpp
new file mode 100644
index 0000000000..533872e849
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/DtxHandlerImpl.cpp
@@ -0,0 +1,171 @@
+/*
+ *
+ * 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 "DtxHandlerImpl.h"
+
+#include <boost/format.hpp>
+#include "Broker.h"
+#include "qpid/framing/constants.h"
+#include "qpid/framing/Array.h"
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+using std::string;
+
+DtxHandlerImpl::DtxHandlerImpl(SemanticState& s) : HandlerImpl(s) {}
+
+// DtxDemarcationHandler:
+
+
+void DtxHandlerImpl::select()
+{
+ state.selectDtx();
+}
+
+DtxDemarcationEndResult DtxHandlerImpl::end(u_int16_t /*ticket*/,
+ const string& xid,
+ bool fail,
+ bool suspend)
+{
+ try {
+ if (fail) {
+ state.endDtx(xid, true);
+ if (suspend) {
+ throw CommandInvalidException(QPID_MSG("End and suspend cannot both be set."));
+ } else {
+ return DtxDemarcationEndResult(XA_RBROLLBACK);
+ }
+ } else {
+ if (suspend) {
+ state.suspendDtx(xid);
+ } else {
+ state.endDtx(xid, false);
+ }
+ return DtxDemarcationEndResult(XA_OK);
+ }
+ } catch (const DtxTimeoutException& e) {
+ return DtxDemarcationEndResult(XA_RBTIMEOUT);
+ }
+}
+
+DtxDemarcationStartResult DtxHandlerImpl::start(u_int16_t /*ticket*/,
+ const string& xid,
+ bool join,
+ bool resume)
+{
+ if (join && resume) {
+ throw CommandInvalidException(QPID_MSG("Join and resume cannot both be set."));
+ }
+ try {
+ if (resume) {
+ state.resumeDtx(xid);
+ } else {
+ state.startDtx(xid, getBroker().getDtxManager(), join);
+ }
+ return DtxDemarcationStartResult(XA_OK);
+ } catch (const DtxTimeoutException& e) {
+ return DtxDemarcationStartResult(XA_RBTIMEOUT);
+ }
+}
+
+// DtxCoordinationHandler:
+
+DtxCoordinationPrepareResult DtxHandlerImpl::prepare(u_int16_t /*ticket*/,
+ const string& xid)
+{
+ try {
+ bool ok = getBroker().getDtxManager().prepare(xid);
+ return DtxCoordinationPrepareResult(ok ? XA_OK : XA_RBROLLBACK);
+ } catch (const DtxTimeoutException& e) {
+ return DtxCoordinationPrepareResult(XA_RBTIMEOUT);
+ }
+}
+
+DtxCoordinationCommitResult DtxHandlerImpl::commit(u_int16_t /*ticket*/,
+ const string& xid,
+ bool onePhase)
+{
+ try {
+ bool ok = getBroker().getDtxManager().commit(xid, onePhase);
+ return DtxCoordinationCommitResult(ok ? XA_OK : XA_RBROLLBACK);
+ } catch (const DtxTimeoutException& e) {
+ return DtxCoordinationCommitResult(XA_RBTIMEOUT);
+ }
+}
+
+
+DtxCoordinationRollbackResult DtxHandlerImpl::rollback(u_int16_t /*ticket*/,
+ const string& xid )
+{
+ try {
+ getBroker().getDtxManager().rollback(xid);
+ return DtxCoordinationRollbackResult(XA_OK);
+ } catch (const DtxTimeoutException& e) {
+ return DtxCoordinationRollbackResult(XA_RBTIMEOUT);
+ }
+}
+
+DtxCoordinationRecoverResult DtxHandlerImpl::recover(u_int16_t /*ticket*/,
+ bool /*startscan*/,
+ bool /*endscan*/ )
+{
+ //TODO: what do startscan and endscan actually mean?
+
+ // response should hold on key value pair with key = 'xids' and
+ // value = sequence of xids
+
+ // until sequences are supported (0-10 encoding), an alternate
+ // scheme is used for testing:
+ //
+ // key = 'xids' and value = a longstr containing shortstrs for each xid
+ //
+ // note that this restricts the length of the xids more than is
+ // strictly 'legal', but that is ok for testing
+ std::set<std::string> xids;
+ getBroker().getStore().collectPreparedXids(xids);
+
+ //TODO: remove the need to copy from one container type to another
+ std::vector<std::string> data;
+ for (std::set<std::string>::iterator i = xids.begin(); i != xids.end(); i++) {
+ data.push_back(*i);
+ }
+ Array indoubt(data);
+ return DtxCoordinationRecoverResult(indoubt);
+}
+
+void DtxHandlerImpl::forget(u_int16_t /*ticket*/,
+ const string& xid)
+{
+ //Currently no heuristic completion is supported, so this should never be used.
+ throw CommandInvalidException(QPID_MSG("Forget is invalid. Branch with xid " << xid << " not heuristically completed!"));
+}
+
+DtxCoordinationGetTimeoutResult DtxHandlerImpl::getTimeout(const string& xid)
+{
+ uint32_t timeout = getBroker().getDtxManager().getTimeout(xid);
+ return DtxCoordinationGetTimeoutResult(timeout);
+}
+
+
+void DtxHandlerImpl::setTimeout(u_int16_t /*ticket*/,
+ const string& xid,
+ u_int32_t timeout)
+{
+ getBroker().getDtxManager().setTimeout(xid, timeout);
+}
+
+
diff --git a/qpid/cpp/src/qpid/broker/DtxHandlerImpl.h b/qpid/cpp/src/qpid/broker/DtxHandlerImpl.h
new file mode 100644
index 0000000000..5bc9d5142a
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/DtxHandlerImpl.h
@@ -0,0 +1,67 @@
+#ifndef _broker_DtxHandlerImpl_h
+#define _broker_DtxHandlerImpl_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/framing/AMQP_ServerOperations.h"
+#include "qpid/framing/AMQP_ClientProxy.h"
+#include "HandlerImpl.h"
+
+namespace qpid {
+namespace broker {
+
+class DtxHandlerImpl
+ : public HandlerImpl,
+ public framing::AMQP_ServerOperations::DtxCoordinationHandler,
+ public framing::AMQP_ServerOperations::DtxDemarcationHandler
+{
+public:
+ DtxHandlerImpl(SemanticState&);
+
+ // DtxCoordinationHandler:
+
+ framing::DtxCoordinationCommitResult commit(u_int16_t ticket, const std::string& xid, bool onePhase);
+
+ void forget(u_int16_t ticket, const std::string& xid);
+
+ framing::DtxCoordinationGetTimeoutResult getTimeout(const std::string& xid);
+
+ framing::DtxCoordinationPrepareResult prepare(u_int16_t ticket, const std::string& xid);
+
+ framing::DtxCoordinationRecoverResult recover(u_int16_t ticket, bool startscan, bool endscan);
+
+ framing::DtxCoordinationRollbackResult rollback(u_int16_t ticket, const std::string& xid);
+
+ void setTimeout(u_int16_t ticket, const std::string& xid, u_int32_t timeout);
+
+ // DtxDemarcationHandler:
+
+ framing::DtxDemarcationEndResult end(u_int16_t ticket, const std::string& xid, bool fail, bool suspend);
+
+ void select();
+
+ framing::DtxDemarcationStartResult start(u_int16_t ticket, const std::string& xid, bool join, bool resume);
+};
+
+
+}} // namespace qpid::broker
+
+
+
+#endif /*!_broker_DtxHandlerImpl_h*/
diff --git a/qpid/cpp/src/qpid/broker/DtxManager.cpp b/qpid/cpp/src/qpid/broker/DtxManager.cpp
new file mode 100644
index 0000000000..fb6b3f019e
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/DtxManager.cpp
@@ -0,0 +1,172 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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 namespace qpid::ptr_map;
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+DtxManager::DtxManager() : store(0) {}
+
+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 InvalidArgumentException(QPID_MSG("Unrecognised xid " << xid));
+ }
+ return get_pointer(i);
+}
+
+void DtxManager::remove(const std::string& xid)
+{
+ Mutex::ScopedLock locker(lock);
+ WorkMap::iterator i = work.find(xid);
+ if (i == work.end()) {
+ throw InvalidArgumentException(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 CommandInvalidException(QPID_MSG("Xid " << xid << " is already known (use 'join' to add work to an existing xid)"));
+ } else {
+ return get_pointer(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 {
+ get_pointer(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)
+{
+ assert (store == 0 && _store != 0);
+ store = _store;
+}
diff --git a/qpid/cpp/src/qpid/broker/DtxManager.h b/qpid/cpp/src/qpid/broker/DtxManager.h
new file mode 100644
index 0000000000..fa5c62c233
--- /dev/null
+++ b/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();
+ ~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/qpid/cpp/src/qpid/broker/DtxTimeout.cpp b/qpid/cpp/src/qpid/broker/DtxTimeout.cpp
new file mode 100644
index 0000000000..8e0a7741c4
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/broker/DtxTimeout.h b/qpid/cpp/src/qpid/broker/DtxTimeout.h
new file mode 100644
index 0000000000..6e949eab0d
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/broker/DtxWorkRecord.cpp b/qpid/cpp/src/qpid/broker/DtxWorkRecord.cpp
new file mode 100644
index 0000000000..fe9e42ca32
--- /dev/null
+++ b/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 CommandInvalidException(QPID_MSG("Branch with xid " << xid << " has been prepared, one-phase option not valid!"));
+ }
+
+ store->commit(*txn);
+ txn.reset();
+
+ 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 CommandInvalidException(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);
+ 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 CommandInvalidException(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();
+ }
+ 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/qpid/cpp/src/qpid/broker/DtxWorkRecord.h b/qpid/cpp/src/qpid/broker/DtxWorkRecord.h
new file mode 100644
index 0000000000..6677784c32
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/broker/Exchange.cpp b/qpid/cpp/src/qpid/broker/Exchange.cpp
new file mode 100644
index 0000000000..47d616cf16
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/Exchange.cpp
@@ -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.
+ *
+ */
+
+#include "Exchange.h"
+#include "ExchangeRegistry.h"
+#include "qpid/management/ManagementAgent.h"
+
+using namespace qpid::broker;
+using qpid::framing::Buffer;
+using qpid::framing::FieldTable;
+using qpid::management::ManagementAgent;
+using qpid::management::ManagementObject;
+using qpid::management::Manageable;
+using qpid::management::Args;
+
+Exchange::Exchange (const string& _name, Manageable* parent) :
+ name(_name), durable(false), persistenceId(0)
+{
+ if (parent != 0)
+ {
+ ManagementAgent::shared_ptr agent = ManagementAgent::getAgent ();
+ if (agent.get () != 0)
+ {
+ mgmtExchange = management::Exchange::shared_ptr
+ (new management::Exchange (this, parent, _name));
+ 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)
+{
+ if (parent != 0)
+ {
+ ManagementAgent::shared_ptr agent = ManagementAgent::getAgent ();
+ if (agent.get () != 0)
+ {
+ mgmtExchange = management::Exchange::shared_ptr
+ (new management::Exchange (this, parent, _name));
+ agent->addObject (mgmtExchange);
+ }
+ }
+}
+
+Exchange::~Exchange ()
+{
+ if (mgmtExchange.get () != 0)
+ mgmtExchange->resourceDestroy ();
+}
+
+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);
+
+ return exchanges.declare(name, type, durable, args).first;
+}
+
+void Exchange::encode(Buffer& buffer) const
+{
+ buffer.putShortString(name);
+ buffer.putOctet(durable);
+ buffer.putShortString(getType());
+ buffer.put(args);
+}
+
+uint32_t Exchange::encodedSize() const
+{
+ return name.size() + 1/*short string size*/
+ + 1 /*durable*/
+ + getType().size() + 1/*short string size*/
+ + args.size();
+}
+
+ManagementObject::shared_ptr Exchange::GetManagementObject (void) const
+{
+ return dynamic_pointer_cast<ManagementObject> (mgmtExchange);
+}
+
+Exchange::Binding::Binding(const string& _key, Queue::shared_ptr _queue, Exchange* parent,
+ FieldTable _args)
+ : queue(_queue), key(_key), args(_args)
+{
+ if (parent != 0)
+ {
+ ManagementAgent::shared_ptr agent = ManagementAgent::getAgent ();
+ if (agent.get() != 0)
+ {
+ ManagementObject::shared_ptr mo = queue->GetManagementObject();
+ if (mo.get() != 0)
+ {
+ uint64_t queueId = mo->getObjectId();
+ mgmtBinding = management::Binding::shared_ptr
+ (new management::Binding (this, (Manageable*) parent, queueId, key, args));
+ agent->addObject (mgmtBinding);
+ }
+ }
+ }
+}
+
+Exchange::Binding::~Binding ()
+{
+ if (mgmtBinding.get () != 0)
+ mgmtBinding->resourceDestroy ();
+}
+
+ManagementObject::shared_ptr Exchange::Binding::GetManagementObject () const
+{
+ return dynamic_pointer_cast<ManagementObject> (mgmtBinding);
+}
+
+Manageable::status_t Exchange::Binding::ManagementMethod (uint32_t, Args&)
+{
+ return Manageable::STATUS_UNKNOWN_METHOD;
+}
diff --git a/qpid/cpp/src/qpid/broker/Exchange.h b/qpid/cpp/src/qpid/broker/Exchange.h
new file mode 100644
index 0000000000..7902eb4219
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/Exchange.h
@@ -0,0 +1,109 @@
+#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/management/Manageable.h"
+#include "qpid/management/Exchange.h"
+#include "qpid/management/Binding.h"
+
+namespace qpid {
+ namespace broker {
+ using std::string;
+ class ExchangeRegistry;
+
+ class Exchange : public PersistableExchange, public management::Manageable {
+ private:
+ const string name;
+ const bool durable;
+ qpid::framing::FieldTable args;
+ boost::shared_ptr<Exchange> alternate;
+ uint32_t alternateUsers;
+ mutable uint64_t persistenceId;
+
+ protected:
+ 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;
+ management::Binding::shared_ptr mgmtBinding;
+
+ Binding(const std::string& key, const Queue::shared_ptr queue, Exchange* parent = 0,
+ framing::FieldTable args = framing::FieldTable ());
+ ~Binding ();
+ management::ManagementObject::shared_ptr GetManagementObject () const;
+ management::Manageable::status_t ManagementMethod (uint32_t methodId, management::Args& args);
+ };
+
+ management::Exchange::shared_ptr mgmtExchange;
+
+ public:
+ typedef boost::shared_ptr<Exchange> shared_ptr;
+
+ explicit Exchange(const string& name, management::Manageable* parent = 0);
+ Exchange(const string& _name, bool _durable, const qpid::framing::FieldTable& _args,
+ management::Manageable* parent = 0);
+ virtual ~Exchange();
+
+ const 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 string getType() const = 0;
+ virtual bool bind(Queue::shared_ptr queue, const string& routingKey, const qpid::framing::FieldTable* args) = 0;
+ virtual bool unbind(Queue::shared_ptr queue, const string& routingKey, const qpid::framing::FieldTable* args) = 0;
+ virtual bool isBound(Queue::shared_ptr queue, const string* const routingKey, const qpid::framing::FieldTable* const args) = 0;
+ virtual void route(Deliverable& msg, const string& routingKey, const qpid::framing::FieldTable* args) = 0;
+
+ //PersistableExchange:
+ void setPersistenceId(uint64_t id) const { persistenceId = id; }
+ 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::shared_ptr GetManagementObject (void) const;
+ management::Manageable::status_t
+ ManagementMethod (uint32_t, management::Args&) { return management::Manageable::STATUS_UNKNOWN_METHOD; }
+ };
+ }
+}
+
+
+#endif /*!_broker_Exchange.cpp_h*/
diff --git a/qpid/cpp/src/qpid/broker/ExchangeRegistry.cpp b/qpid/cpp/src/qpid/broker/ExchangeRegistry.cpp
new file mode 100644
index 0000000000..58d9d5efb8
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/ExchangeRegistry.cpp
@@ -0,0 +1,92 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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{
+ throw UnknownExchangeTypeException();
+ }
+ 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;
+}
+
+namespace
+{
+const std::string empty;
+}
+
+Exchange::shared_ptr ExchangeRegistry::getDefault()
+{
+ return get(empty);
+}
diff --git a/qpid/cpp/src/qpid/broker/ExchangeRegistry.h b/qpid/cpp/src/qpid/broker/ExchangeRegistry.h
new file mode 100644
index 0000000000..f39bd661fa
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/ExchangeRegistry.h
@@ -0,0 +1,61 @@
+#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 <map>
+#include "Exchange.h"
+#include "MessageStore.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/sys/Monitor.h"
+#include "qpid/management/Manageable.h"
+
+namespace qpid {
+namespace broker {
+ struct UnknownExchangeTypeException{};
+
+ class ExchangeRegistry{
+ typedef std::map<std::string, Exchange::shared_ptr> ExchangeMap;
+ ExchangeMap exchanges;
+ qpid::sys::RWlock lock;
+ management::Manageable* parent;
+ public:
+ 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 queues
+ */
+ void setParent (management::Manageable* _parent) { parent = _parent; }
+ };
+}
+}
+
+
+#endif /*!_broker_ExchangeRegistry_h*/
diff --git a/qpid/cpp/src/qpid/broker/FanOutExchange.cpp b/qpid/cpp/src/qpid/broker/FanOutExchange.cpp
new file mode 100644
index 0000000000..df723d2c8f
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/FanOutExchange.cpp
@@ -0,0 +1,126 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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;
+
+FanOutExchange::FanOutExchange(const std::string& _name, Manageable* _parent) :
+ Exchange(_name, _parent)
+{
+ if (mgmtExchange.get() != 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.get() != 0)
+ mgmtExchange->set_type (typeName);
+}
+
+bool FanOutExchange::bind(Queue::shared_ptr queue, const string& /*routingKey*/, const FieldTable* /*args*/){
+ RWlock::ScopedWlock locker(lock);
+ std::vector<Binding::shared_ptr>::iterator i;
+
+ // Add if not already present.
+ for (i = bindings.begin (); i != bindings.end(); i++)
+ if ((*i)->queue == queue)
+ break;
+
+ if (i == bindings.end()) {
+ Binding::shared_ptr binding (new Binding ("", queue, this));
+ bindings.push_back(binding);
+ if (mgmtExchange.get() != 0) {
+ mgmtExchange->inc_bindings ();
+ dynamic_pointer_cast<management::Queue>(queue->GetManagementObject())->inc_bindings();
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool FanOutExchange::unbind(Queue::shared_ptr queue, const string& /*routingKey*/, const FieldTable* /*args*/){
+ RWlock::ScopedWlock locker(lock);
+ std::vector<Binding::shared_ptr>::iterator i;
+
+ for (i = bindings.begin (); i != bindings.end(); i++)
+ if ((*i)->queue == queue)
+ break;
+
+ if (i != bindings.end()) {
+ bindings.erase(i);
+ if (mgmtExchange.get() != 0) {
+ mgmtExchange->dec_bindings ();
+ dynamic_pointer_cast<management::Queue>(queue->GetManagementObject())->dec_bindings();
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void FanOutExchange::route(Deliverable& msg, const string& /*routingKey*/, const FieldTable* /*args*/){
+ RWlock::ScopedRlock locker(lock);
+ uint32_t count(0);
+
+ for(std::vector<Binding::shared_ptr>::iterator i = bindings.begin(); i != bindings.end(); ++i, count++){
+ msg.deliverTo((*i)->queue);
+ if ((*i)->mgmtBinding.get() != 0)
+ (*i)->mgmtBinding->inc_msgMatched ();
+ }
+
+ if (mgmtExchange.get() != 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)
+{
+ std::vector<Binding::shared_ptr>::iterator i;
+
+ for (i = bindings.begin (); i != bindings.end(); i++)
+ if ((*i)->queue == queue)
+ break;
+
+ return i != bindings.end();
+}
+
+
+FanOutExchange::~FanOutExchange() {}
+
+const std::string FanOutExchange::typeName("fanout");
diff --git a/qpid/cpp/src/qpid/broker/FanOutExchange.h b/qpid/cpp/src/qpid/broker/FanOutExchange.h
new file mode 100644
index 0000000000..4bc92f6b28
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/FanOutExchange.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 _FanOutExchange_
+#define _FanOutExchange_
+
+#include <map>
+#include <vector>
+#include "Exchange.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/sys/Monitor.h"
+#include "Queue.h"
+
+namespace qpid {
+namespace broker {
+
+class FanOutExchange : public virtual Exchange {
+ std::vector<Binding::shared_ptr> bindings;
+ qpid::sys::RWlock lock;
+
+ 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();
+};
+
+}
+}
+
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/HandlerImpl.h b/qpid/cpp/src/qpid/broker/HandlerImpl.h
new file mode 100644
index 0000000000..4c51e2a826
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/broker/HeadersExchange.cpp b/qpid/cpp/src/qpid/broker/HeadersExchange.cpp
new file mode 100644
index 0000000000..5196099ed5
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/HeadersExchange.cpp
@@ -0,0 +1,231 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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;
+
+// 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.get() != 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.get() != 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){
+ RWlock::ScopedWlock locker(lock);
+ std::string what = getMatch(args);
+ if (what != all && what != any)
+ throw InternalErrorException(QPID_MSG("Invalid x-match value binding to headers exchange."));
+
+ Bindings::iterator i;
+
+ for (i = bindings.begin(); i != bindings.end(); i++)
+ if (i->first == *args && i->second->queue == queue)
+ break;
+
+ if (i == bindings.end()) {
+ Binding::shared_ptr binding (new Binding (bindingKey, queue, this, *args));
+ HeaderMap headerMap(*args, binding);
+
+ bindings.push_back(headerMap);
+ if (mgmtExchange.get() != 0) {
+ mgmtExchange->inc_bindings ();
+ dynamic_pointer_cast<management::Queue>(queue->GetManagementObject())->inc_bindings();
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool HeadersExchange::unbind(Queue::shared_ptr queue, const string& bindingKey, const FieldTable* args){
+ RWlock::ScopedWlock locker(lock);
+ Bindings::iterator i;
+ for (i = bindings.begin(); i != bindings.end(); i++) {
+ if (bindingKey.empty() && args) {
+ if (i->first == *args && i->second->queue == queue)
+ break;
+ } else {
+ if (i->second->key == bindingKey && i->second->queue == queue)
+ break;
+ }
+ }
+
+ if (i != bindings.end()) {
+ bindings.erase(i);
+ if (mgmtExchange.get() != 0) {
+ mgmtExchange->dec_bindings ();
+ dynamic_pointer_cast<management::Queue>(queue->GetManagementObject())->dec_bindings();
+ }
+ 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
+
+ RWlock::ScopedRlock locker(lock);
+ uint32_t count(0);
+
+ for (Bindings::iterator i = bindings.begin(); i != bindings.end(); ++i, count++) {
+ if (match(i->first, *args)) msg.deliverTo(i->second->queue);
+ if (i->second->mgmtBinding.get() != 0)
+ i->second->mgmtBinding->inc_msgMatched ();
+ }
+
+ if (mgmtExchange.get() != 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)
+{
+ for (Bindings::iterator i = bindings.begin(); i != bindings.end(); ++i) {
+ if ( (!args || equal(i->first, *args)) && (!queue || i->second->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;
+}
+
+
+
diff --git a/qpid/cpp/src/qpid/broker/HeadersExchange.h b/qpid/cpp/src/qpid/broker/HeadersExchange.h
new file mode 100644
index 0000000000..6e101e193a
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/HeadersExchange.h
@@ -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.
+ *
+ */
+#ifndef _HeadersExchange_
+#define _HeadersExchange_
+
+#include <vector>
+#include "Exchange.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/sys/Monitor.h"
+#include "Queue.h"
+
+namespace qpid {
+namespace broker {
+
+
+class HeadersExchange : public virtual Exchange {
+ typedef std::pair<qpid::framing::FieldTable, Binding::shared_ptr> HeaderMap;
+ typedef std::vector<HeaderMap> Bindings;
+
+ Bindings bindings;
+ qpid::sys::RWlock 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/qpid/cpp/src/qpid/broker/IncomingExecutionContext.cpp b/qpid/cpp/src/qpid/broker/IncomingExecutionContext.cpp
new file mode 100644
index 0000000000..6c6cae6740
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/IncomingExecutionContext.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 "IncomingExecutionContext.h"
+#include "qpid/Exception.h"
+
+namespace qpid {
+namespace broker {
+
+using boost::intrusive_ptr;
+using qpid::framing::AccumulatedAck;
+using qpid::framing::SequenceNumber;
+using qpid::framing::SequenceNumberSet;
+
+void IncomingExecutionContext::noop()
+{
+ complete(next());
+}
+
+void IncomingExecutionContext::flush()
+{
+ for (Messages::iterator i = incomplete.begin(); i != incomplete.end(); ) {
+ if ((*i)->isEnqueueComplete()) {
+ complete((*i)->getCommandId());
+ i = incomplete.erase(i);
+ } else {
+ i++;
+ }
+ }
+ window.lwm = completed.mark;
+}
+
+void IncomingExecutionContext::sync()
+{
+ while (completed.mark < window.hwm) {
+ wait();
+ }
+}
+
+void IncomingExecutionContext::sync(const SequenceNumber& point)
+{
+ while (!isComplete(point)) {
+ wait();
+ }
+}
+
+/**
+ * Every call to next() should be followed be either a call to
+ * complete() - in the case of commands, which are always synchronous
+ * - or track() - in the case of messages which may be asynchronously
+ * stored.
+ */
+SequenceNumber IncomingExecutionContext::next()
+{
+ return ++window.hwm;
+}
+
+void IncomingExecutionContext::complete(const SequenceNumber& command)
+{
+ completed.update(command, command);
+}
+
+void IncomingExecutionContext::track(intrusive_ptr<Message> msg)
+{
+ if (msg->isEnqueueComplete()) {
+ complete(msg->getCommandId());
+ } else {
+ incomplete.push_back(msg);
+ }
+}
+
+bool IncomingExecutionContext::isComplete(const SequenceNumber& command)
+{
+ if (command > window.hwm) {
+ throw Exception(QPID_MSG("Bad sync request: point exceeds last command received ["
+ << command.getValue() << " > " << window.hwm.getValue() << "]"));
+ }
+
+ return completed.covers(command);
+}
+
+
+const SequenceNumber& IncomingExecutionContext::getMark()
+{
+ return completed.mark;
+}
+
+SequenceNumberSet IncomingExecutionContext::getRange()
+{
+ SequenceNumberSet range;
+ completed.collectRanges(range);
+ return range;
+}
+
+void IncomingExecutionContext::wait()
+{
+ check();
+ // for IO flush on the store
+ for (Messages::iterator i = incomplete.begin(); i != incomplete.end(); i++) {
+ (*i)->flush();
+ }
+ incomplete.front()->waitForEnqueueComplete();
+ flush();
+}
+
+/**
+ * This is a check of internal state consistency.
+ */
+void IncomingExecutionContext::check()
+{
+ if (incomplete.empty()) {
+ if (window.hwm != completed.mark) {
+ //can only happen if there is a call to next() without a
+ //corresponding call to completed() or track() - or if
+ //there is a logical error in flush() or
+ //AccumulatedAck::update()
+ throw Exception(QPID_MSG("Completion tracking error: window.hwm="
+ << window.hwm.getValue() << ", completed.mark="
+ << completed.mark.getValue()));
+ }
+ }
+}
+
+}}
+
diff --git a/qpid/cpp/src/qpid/broker/IncomingExecutionContext.h b/qpid/cpp/src/qpid/broker/IncomingExecutionContext.h
new file mode 100644
index 0000000000..7380e9ae64
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/IncomingExecutionContext.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 _IncomingExecutionContext_
+#define _IncomingExecutionContext_
+
+#include "Message.h"
+
+#include "qpid/framing/AccumulatedAck.h"
+#include "qpid/framing/SequenceNumber.h"
+
+#include <boost/intrusive_ptr.hpp>
+
+namespace qpid {
+namespace broker {
+
+class IncomingExecutionContext
+{
+ typedef std::list<boost::intrusive_ptr<Message> > Messages;
+ framing::Window window;
+ framing::AccumulatedAck completed;
+ Messages incomplete;
+
+ bool isComplete(const framing::SequenceNumber& command);
+ void check();
+ void wait();
+public:
+ void noop();
+ void flush();
+ void sync();
+ void sync(const framing::SequenceNumber& point);
+ framing::SequenceNumber next();
+ void complete(const framing::SequenceNumber& command);
+ void track(boost::intrusive_ptr<Message>);
+
+ const framing::SequenceNumber& getMark();
+ framing::SequenceNumberSet getRange();
+
+};
+
+
+}}
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/IncompleteMessageList.cpp b/qpid/cpp/src/qpid/broker/IncompleteMessageList.cpp
new file mode 100644
index 0000000000..dd7bbfc067
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/IncompleteMessageList.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 "IncompleteMessageList.h"
+
+#include "Message.h"
+
+namespace qpid {
+namespace broker {
+
+void IncompleteMessageList::add(boost::intrusive_ptr<Message> msg)
+{
+ incomplete.push_back(msg);
+}
+
+void IncompleteMessageList::process(CompletionListener l, bool sync)
+{
+ while (!incomplete.empty()) {
+ boost::intrusive_ptr<Message>& msg = incomplete.front();
+ if (!msg->isEnqueueComplete()) {
+ if (sync){
+ msg->flush();
+ msg->waitForEnqueueComplete();
+ } else {
+ //leave the message as incomplete for now
+ return;
+ }
+ }
+ l(msg);
+ incomplete.pop_front();
+ }
+}
+
+}}
diff --git a/qpid/cpp/src/qpid/broker/IncompleteMessageList.h b/qpid/cpp/src/qpid/broker/IncompleteMessageList.h
new file mode 100644
index 0000000000..2cfd7bfee5
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/IncompleteMessageList.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 _IncompleteMessageList_
+#define _IncompleteMessageList_
+
+#include <list>
+#include <boost/intrusive_ptr.hpp>
+#include <boost/function.hpp>
+
+namespace qpid {
+namespace broker {
+
+class Message;
+
+class IncompleteMessageList
+{
+ typedef std::list< boost::intrusive_ptr<Message> > Messages;
+ Messages incomplete;
+
+public:
+ typedef boost::function<void(boost::intrusive_ptr<Message>)> CompletionListener;
+
+ void add(boost::intrusive_ptr<Message> msg);
+ void process(CompletionListener l, bool sync);
+};
+
+
+}}
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/Message.cpp b/qpid/cpp/src/qpid/broker/Message.cpp
new file mode 100644
index 0000000000..b60a95228d
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/Message.cpp
@@ -0,0 +1,249 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/framing/frame_functors.h"
+#include "qpid/framing/BasicPublishBody.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"
+
+using boost::intrusive_ptr;
+using namespace qpid::broker;
+using namespace qpid::framing;
+using std::string;
+
+TransferAdapter Message::TRANSFER;
+PreviewAdapter Message::TRANSFER_99_0;
+
+Message::Message(const SequenceNumber& id) : frames(id), persistenceId(0), redelivered(false), loaded(false), staged(false), publisher(0), adapter(0) {}
+
+Message::~Message()
+{
+ 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");
+ }
+ }
+}
+
+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);
+}
+
+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
+ 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::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();
+ uint64_t expectedSize(frames.getHeaders()->getContentLength());
+ intrusive_ptr<const PersistableMessage> pmsg(this);
+ for (uint64_t offset = 0; offset < expectedSize; offset += maxContentSize)
+ {
+ uint64_t remaining = expectedSize - offset;
+ AMQFrame frame(in_place<AMQContentBody>());
+ string& data = frame.castBody<AMQContentBody>()->getData();
+
+ store->loadContent(queue, pmsg, data, offset,
+ remaining > maxContentSize ? maxContentSize : remaining);
+ frame.setBof(false);
+ frame.setEof(true);
+ if (offset > 0) {
+ frame.setBos(false);
+ }
+ if (remaining > maxContentSize) {
+ frame.setEos(false);
+ }
+ 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
+{
+ 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_99_0;
+ } else if(frames.isA<Message010TransferBody>()) {
+ 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;
+}
diff --git a/qpid/cpp/src/qpid/broker/Message.h b/qpid/cpp/src/qpid/broker/Message.h
new file mode 100644
index 0000000000..561cdede59
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/Message.h
@@ -0,0 +1,145 @@
+#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 <string>
+#include <boost/shared_ptr.hpp>
+#include <boost/variant.hpp>
+#include "PersistableMessage.h"
+#include "MessageAdapter.h"
+#include "qpid/framing/amqp_types.h"
+
+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::intrusive_ptr<Message> shared_ptr;
+
+ 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();
+
+ framing::FrameSet& getFrames() { return frames; }
+ const framing::FrameSet& getFrames() const { return frames; }
+
+ template <class T> T* getProperties() {
+ return frames.getHeaders()->get<T>(true);
+ }
+
+ template <class T> const T* getProperties() const {
+ return frames.getHeaders()->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 sendContent(Queue& queue, framing::FrameHandler& out, uint16_t maxFrameSize) const;
+ void sendHeader(framing::FrameHandler& out, uint16_t maxFrameSize) const;
+
+ bool isContentLoaded() const;
+
+ private:
+ framing::FrameSet frames;
+ mutable boost::shared_ptr<Exchange> exchange;
+ mutable uint64_t persistenceId;
+ bool redelivered;
+ bool loaded;
+ bool staged;
+ ConnectionToken* publisher;
+ mutable MessageAdapter* adapter;
+
+ static TransferAdapter TRANSFER;
+ static PreviewAdapter TRANSFER_99_0;
+
+ MessageAdapter& getAdapter() const;
+};
+
+}}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/MessageAdapter.cpp b/qpid/cpp/src/qpid/broker/MessageAdapter.cpp
new file mode 100644
index 0000000000..ea2882b474
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/MessageAdapter.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 "MessageAdapter.h"
+
+namespace {
+ const std::string empty;
+}
+
+namespace qpid {
+namespace broker{
+
+ std::string TransferAdapter::getRoutingKey(const framing::FrameSet& f)
+ {
+ const framing::DeliveryProperties010* p = f.getHeaders()->get<framing::DeliveryProperties010>();
+ return p ? p->getRoutingKey() : empty;
+ }
+
+ std::string TransferAdapter::getExchange(const framing::FrameSet& f)
+ {
+ return f.as<framing::Message010TransferBody>()->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::MessageProperties010* p = f.getHeaders()->get<framing::MessageProperties010>();
+ return p ? &(p->getApplicationHeaders()) : 0;
+ }
+
+ bool TransferAdapter::isPersistent(const framing::FrameSet& f)
+ {
+ const framing::DeliveryProperties010* p = f.getHeaders()->get<framing::DeliveryProperties010>();
+ return p && p->getDeliveryMode() == 2;
+ }
+
+ bool TransferAdapter::requiresAccept(const framing::FrameSet& f)
+ {
+ const framing::Message010TransferBody* b = f.as<framing::Message010TransferBody>();
+ return b && b->getAcceptMode();
+ }
+
+ std::string PreviewAdapter::getExchange(const framing::FrameSet& f)
+ {
+ return f.as<framing::MessageTransferBody>()->getDestination();
+ }
+
+ std::string PreviewAdapter::getRoutingKey(const framing::FrameSet& f)
+ {
+ const framing::DeliveryProperties* p = f.getHeaders()->get<framing::DeliveryProperties>();
+ return p ? p->getRoutingKey() : empty;
+ }
+
+ const framing::FieldTable* PreviewAdapter::getApplicationHeaders(const framing::FrameSet& f)
+ {
+ const framing::MessageProperties* p = f.getHeaders()->get<framing::MessageProperties>();
+ return p ? &(p->getApplicationHeaders()) : 0;
+ }
+
+ bool PreviewAdapter::isPersistent(const framing::FrameSet& f)
+ {
+ const framing::DeliveryProperties* p = f.getHeaders()->get<framing::DeliveryProperties>();
+ return p && p->getDeliveryMode() == 2;
+ }
+
+}}
diff --git a/qpid/cpp/src/qpid/broker/MessageAdapter.h b/qpid/cpp/src/qpid/broker/MessageAdapter.h
new file mode 100644
index 0000000000..9759f320ac
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/MessageAdapter.h
@@ -0,0 +1,71 @@
+#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/BasicPublishBody.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/FrameSet.h"
+#include "qpid/framing/DeliveryProperties.h"
+#include "qpid/framing/MessageProperties.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/framing/Message010TransferBody.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);
+};
+
+struct PreviewAdapter : TransferAdapter
+{
+ std::string getExchange(const framing::FrameSet& f);
+ std::string getRoutingKey(const framing::FrameSet& f);
+ const framing::FieldTable* getApplicationHeaders(const framing::FrameSet& f);
+ bool isPersistent(const framing::FrameSet& f);
+};
+
+}}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/MessageBuilder.cpp b/qpid/cpp/src/qpid/broker/MessageBuilder.cpp
new file mode 100644
index 0000000000..eda71ed3da
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/MessageBuilder.cpp
@@ -0,0 +1,123 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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 "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) {
+ 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/qpid/cpp/src/qpid/broker/MessageBuilder.h b/qpid/cpp/src/qpid/broker/MessageBuilder.h
new file mode 100644
index 0000000000..395de024ab
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/broker/MessageDelivery.cpp b/qpid/cpp/src/qpid/broker/MessageDelivery.cpp
new file mode 100644
index 0000000000..9ef7090cd9
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/MessageDelivery.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 "MessageDelivery.h"
+
+#include "DeliveryToken.h"
+#include "Message.h"
+#include "Queue.h"
+#include "qpid/framing/FrameHandler.h"
+#include "qpid/framing/BasicDeliverBody.h"
+#include "qpid/framing/BasicGetOkBody.h"
+#include "qpid/framing/MessageTransferBody.h"
+
+
+using namespace boost;
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+namespace qpid{
+namespace broker{
+
+struct BaseToken : DeliveryToken
+{
+ virtual ~BaseToken() {}
+ virtual AMQFrame sendMethod(intrusive_ptr<Message> msg, DeliveryId id) = 0;
+};
+
+struct BasicGetToken : BaseToken
+{
+ typedef boost::shared_ptr<BasicGetToken> shared_ptr;
+
+ Queue::shared_ptr queue;
+
+ BasicGetToken(Queue::shared_ptr q) : queue(q) {}
+
+ AMQFrame sendMethod(intrusive_ptr<Message> msg, DeliveryId id)
+ {
+ return AMQFrame(in_place<BasicGetOkBody>(
+ ProtocolVersion(), id.getValue(),
+ msg->getRedelivered(), msg->getExchangeName(),
+ msg->getRoutingKey(), queue->getMessageCount()));
+ }
+};
+
+struct BasicConsumeToken : BaseToken
+{
+ typedef boost::shared_ptr<BasicConsumeToken> shared_ptr;
+
+ const string consumer;
+
+ BasicConsumeToken(const string c) : consumer(c) {}
+
+ AMQFrame sendMethod(intrusive_ptr<Message> msg, DeliveryId id)
+ {
+ return AMQFrame(in_place<BasicDeliverBody>(
+ ProtocolVersion(), consumer, id.getValue(),
+ msg->getRedelivered(), msg->getExchangeName(),
+ msg->getRoutingKey()));
+ }
+
+};
+
+struct MessageDeliveryToken : BaseToken
+{
+ const std::string destination;
+ const u_int8_t confirmMode;
+ const u_int8_t acquireMode;
+ const bool isPreview;
+
+ MessageDeliveryToken(const std::string& d, u_int8_t c, u_int8_t a, bool p) :
+ destination(d), confirmMode(c), acquireMode(a), isPreview(p) {}
+
+ AMQFrame sendMethod(intrusive_ptr<Message> msg, DeliveryId /*id*/)
+ {
+ //may need to set the redelivered flag:
+ if (isPreview) {
+ if (msg->getRedelivered()){
+ msg->getProperties<DeliveryProperties>()->setRedelivered(true);
+ }
+ return AMQFrame(in_place<MessageTransferBody>(
+ ProtocolVersion(), 0, destination,
+ confirmMode, acquireMode));
+ } else {
+ if (msg->getRedelivered()){
+ msg->getProperties<DeliveryProperties010>()->setRedelivered(true);
+ }
+ return AMQFrame(in_place<Message010TransferBody>(
+ ProtocolVersion(), destination, confirmMode, acquireMode));
+ }
+ }
+};
+
+}
+}
+
+DeliveryToken::shared_ptr MessageDelivery::getBasicGetToken(Queue::shared_ptr queue)
+{
+ return DeliveryToken::shared_ptr(new BasicGetToken(queue));
+}
+
+DeliveryToken::shared_ptr MessageDelivery::getBasicConsumeToken(const string& consumer)
+{
+ return DeliveryToken::shared_ptr(new BasicConsumeToken(consumer));
+}
+
+DeliveryToken::shared_ptr MessageDelivery::getMessageDeliveryToken(const std::string& destination,
+ u_int8_t confirmMode, u_int8_t acquireMode)
+{
+ return DeliveryToken::shared_ptr(new MessageDeliveryToken(destination, confirmMode, acquireMode, false));
+}
+
+DeliveryToken::shared_ptr MessageDelivery::getPreviewMessageDeliveryToken(const std::string& destination,
+ u_int8_t confirmMode, u_int8_t acquireMode)
+{
+ return DeliveryToken::shared_ptr(new MessageDeliveryToken(destination, confirmMode, acquireMode, true));
+}
+
+void MessageDelivery::deliver(QueuedMessage& msg,
+ framing::FrameHandler& handler,
+ DeliveryId id,
+ DeliveryToken::shared_ptr token,
+ uint16_t framesize)
+{
+ //currently a message published from one class and delivered to
+ //another may well have the wrong headers; however we will only
+ //have one content class for 0-10 proper
+
+ boost::shared_ptr<BaseToken> t = dynamic_pointer_cast<BaseToken>(token);
+ AMQFrame method = t->sendMethod(msg.payload, id);
+ method.setEof(false);
+ handler.handle(method);
+ msg.payload->sendHeader(handler, framesize);
+ msg.payload->sendContent(*(msg.queue), handler, framesize);
+}
diff --git a/qpid/cpp/src/qpid/broker/MessageDelivery.h b/qpid/cpp/src/qpid/broker/MessageDelivery.h
new file mode 100644
index 0000000000..564e1456a0
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/MessageDelivery.h
@@ -0,0 +1,58 @@
+#ifndef _broker_MessageDelivery_h
+#define _broker_MessageDelivery_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 "DeliveryId.h"
+#include "Consumer.h"
+#include "qpid/framing/FrameHandler.h"
+
+namespace qpid {
+namespace broker {
+
+class DeliveryToken;
+class Message;
+class Queue;
+
+/**
+ * Encapsulates the different options for message delivery currently supported.
+ */
+class MessageDelivery {
+public:
+ static boost::shared_ptr<DeliveryToken> getBasicGetToken(boost::shared_ptr<Queue> queue);
+ static boost::shared_ptr<DeliveryToken> getBasicConsumeToken(const std::string& consumer);
+ static boost::shared_ptr<DeliveryToken> getPreviewMessageDeliveryToken(const std::string& destination,
+ u_int8_t confirmMode,
+ u_int8_t acquireMode);
+ static boost::shared_ptr<DeliveryToken> getMessageDeliveryToken(const std::string& destination,
+ u_int8_t confirmMode,
+ u_int8_t acquireMode);
+
+ static void deliver(QueuedMessage& msg, framing::FrameHandler& out,
+ DeliveryId deliveryTag, boost::shared_ptr<DeliveryToken> token, uint16_t framesize);
+};
+
+}
+}
+
+
+#endif /*!_broker_MessageDelivery_h*/
diff --git a/qpid/cpp/src/qpid/broker/MessageHandlerImpl.cpp b/qpid/cpp/src/qpid/broker/MessageHandlerImpl.cpp
new file mode 100644
index 0000000000..64c0282963
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/MessageHandlerImpl.cpp
@@ -0,0 +1,210 @@
+/*
+ *
+ * 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/log/Statement.h"
+#include "MessageHandlerImpl.h"
+#include "qpid/framing/FramingContent.h"
+#include "Connection.h"
+#include "Broker.h"
+#include "MessageDelivery.h"
+#include "qpid/framing/MessageAppendBody.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "BrokerAdapter.h"
+
+#include <boost/format.hpp>
+#include <boost/cast.hpp>
+#include <boost/bind.hpp>
+
+namespace qpid {
+namespace broker {
+
+using namespace framing;
+
+MessageHandlerImpl::MessageHandlerImpl(SemanticState& s) :
+ HandlerImpl(s),
+ releaseOp(boost::bind(&SemanticState::release, &state, _1, _2, false)),
+ rejectOp(boost::bind(&SemanticState::reject, &state, _1, _2))
+ {}
+
+//
+// Message class method handlers
+//
+
+void
+MessageHandlerImpl::cancel(const string& destination )
+{
+ state.cancel(destination);
+}
+
+void
+MessageHandlerImpl::open(const string& /*reference*/)
+{
+ throw NotImplementedException("References no longer supported");
+}
+
+void
+MessageHandlerImpl::append(const std::string& /*reference*/, const std::string& /*bytes*/)
+{
+ throw NotImplementedException("References no longer supported");
+}
+
+void
+MessageHandlerImpl::close(const string& /*reference*/)
+{
+ throw NotImplementedException("References no longer supported");
+}
+
+void
+MessageHandlerImpl::checkpoint(const string& /*reference*/,
+ const string& /*identifier*/ )
+{
+ throw NotImplementedException("References no longer supported");
+}
+
+void
+MessageHandlerImpl::resume(const string& /*reference*/,
+ const string& /*identifier*/ )
+{
+ throw NotImplementedException("References no longer supported");
+}
+
+void
+MessageHandlerImpl::offset(uint64_t /*value*/ )
+{
+ throw NotImplementedException("References no longer supported");
+}
+
+void
+MessageHandlerImpl::get(uint16_t /*ticket*/,
+ const string& /*queueName*/,
+ const string& /*destination*/,
+ bool /*noAck*/ )
+{
+ throw NotImplementedException("get no longer supported");
+}
+
+void
+MessageHandlerImpl::empty()
+{
+ throw NotImplementedException("empty no longer supported");
+}
+
+void
+MessageHandlerImpl::ok()
+{
+ throw NotImplementedException("Message.Ok no longer supported");
+}
+
+void
+MessageHandlerImpl::qos(uint32_t prefetchSize,
+ uint16_t prefetchCount,
+ bool /*global*/ )
+{
+ //TODO: handle global
+ state.setPrefetchSize(prefetchSize);
+ state.setPrefetchCount(prefetchCount);
+}
+
+void
+MessageHandlerImpl::subscribe(uint16_t /*ticket*/,
+ const string& queueName,
+ const string& destination,
+ bool noLocal,
+ u_int8_t confirmMode,
+ u_int8_t acquireMode,
+ bool exclusive,
+ const framing::FieldTable& filter )
+{
+ Queue::shared_ptr queue = state.getQueue(queueName);
+ if(!destination.empty() && state.exists(destination))
+ throw NotAllowedException(QPID_MSG("Consumer tags must be unique"));
+
+ string tag = destination;
+ state.consume(MessageDelivery::getPreviewMessageDeliveryToken(destination, confirmMode, acquireMode),
+ tag, queue, noLocal, confirmMode == 1, acquireMode == 0, exclusive, &filter);
+}
+
+void
+MessageHandlerImpl::recover(bool requeue)
+{
+ state.recover(requeue);
+}
+
+void
+MessageHandlerImpl::reject(const SequenceNumberSet& transfers, uint16_t /*code*/, const string& /*text*/ )
+{
+ transfers.processRanges(rejectOp);
+}
+
+void MessageHandlerImpl::flow(const std::string& destination, u_int8_t unit, u_int32_t value)
+{
+ if (unit == 0) {
+ //message
+ state.addMessageCredit(destination, value);
+ } else if (unit == 1) {
+ //bytes
+ state.addByteCredit(destination, value);
+ } else {
+ //unknown
+ throw SyntaxErrorException(QPID_MSG("Invalid value for unit " << unit));
+ }
+
+}
+
+void MessageHandlerImpl::flowMode(const std::string& destination, u_int8_t mode)
+{
+ if (mode == 0) {
+ //credit
+ state.setCreditMode(destination);
+ } else if (mode == 1) {
+ //window
+ state.setWindowMode(destination);
+ } else{
+ throw SyntaxErrorException(QPID_MSG("Invalid value for mode " << mode));
+ }
+}
+
+void MessageHandlerImpl::flush(const std::string& destination)
+{
+ state.flush(destination);
+}
+
+void MessageHandlerImpl::stop(const std::string& destination)
+{
+ state.stop(destination);
+}
+
+void MessageHandlerImpl::acquire(const SequenceNumberSet& transfers, u_int8_t /*mode*/)
+{
+ //TODO: implement mode
+
+ SequenceNumberSet results;
+ RangedOperation op = boost::bind(&SemanticState::acquire, &state, _1, _2, boost::ref(results));
+ transfers.processRanges(op);
+ results = results.condense();
+ getProxy().getMessage().acquired(results);
+}
+
+void MessageHandlerImpl::release(const SequenceNumberSet& transfers)
+{
+ transfers.processRanges(releaseOp);
+}
+
+}} // namespace qpid::broker
diff --git a/qpid/cpp/src/qpid/broker/MessageHandlerImpl.h b/qpid/cpp/src/qpid/broker/MessageHandlerImpl.h
new file mode 100644
index 0000000000..dd70f35dbb
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/MessageHandlerImpl.h
@@ -0,0 +1,110 @@
+#ifndef _broker_MessageHandlerImpl_h
+#define _broker_MessageHandlerImpl_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>
+
+#include "qpid/framing/AMQP_ServerOperations.h"
+#include "qpid/framing/AMQP_ClientProxy.h"
+#include "HandlerImpl.h"
+
+#include <boost/function.hpp>
+
+namespace qpid {
+namespace broker {
+
+class Connection;
+class Broker;
+class MessageMessage;
+
+class MessageHandlerImpl :
+ public framing::AMQP_ServerOperations::MessageHandler,
+ public HandlerImpl
+{
+ typedef boost::function<void(DeliveryId, DeliveryId)> RangedOperation;
+ RangedOperation releaseOp;
+ RangedOperation rejectOp;
+
+ public:
+ MessageHandlerImpl(SemanticState&);
+
+ void append(const std::string& reference, const std::string& bytes);
+
+ void cancel(const std::string& destination );
+
+ void checkpoint(const std::string& reference,
+ const std::string& identifier );
+
+ void close(const std::string& reference );
+
+ void empty();
+
+ void get(uint16_t ticket,
+ const std::string& queue,
+ const std::string& destination,
+ bool noAck );
+
+ void offset(uint64_t value);
+
+ void ok();
+
+ void open(const std::string& reference );
+
+ void qos(uint32_t prefetchSize,
+ uint16_t prefetchCount,
+ bool global );
+
+ void recover(bool requeue );
+
+ void reject(const framing::SequenceNumberSet& transfers,
+ uint16_t code,
+ const std::string& text );
+
+ void resume(const std::string& reference,
+ const std::string& identifier );
+
+ void flow(const std::string& destination, u_int8_t unit, u_int32_t value);
+
+ void flowMode(const std::string& destination, u_int8_t mode);
+
+ void flush(const std::string& destination);
+
+ void stop(const std::string& destination);
+
+ void acquire(const framing::SequenceNumberSet& transfers, u_int8_t mode);
+
+ void release(const framing::SequenceNumberSet& transfers);
+
+ void subscribe(u_int16_t ticket,
+ const std::string& queue,
+ const std::string& destination,
+ bool noLocal,
+ u_int8_t confirmMode,
+ u_int8_t acquireMode,
+ bool exclusive,
+ const framing::FieldTable& filter);
+
+};
+
+}} // namespace qpid::broker
+
+
+
+#endif /*!_broker_MessageHandlerImpl_h*/
diff --git a/qpid/cpp/src/qpid/broker/MessageStore.h b/qpid/cpp/src/qpid/broker/MessageStore.h
new file mode 100644
index 0000000000..76469ccc50
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/MessageStore.h
@@ -0,0 +1,195 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 "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 dir the directory to create logs/db's
+ * @param async true, enable async, false, enable sync
+ * @param force true, delete data on mode change, false, error on mode change
+ */
+ 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;
+
+ /**
+ * 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.
+ *
+ * TODO ::If it is know
+ * which queue the message is to be staged/ release to in cases
+ * of flowing tmp messages to disk for memory conservation set
+ * the queue ptr. This allows the store to optimize the read/writes
+ * for that queue and avoid searching based on id. Set queue = 0 for
+ * large message staging when the queue is not known.
+ */
+ virtual void stage(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(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,
+ 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, 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, 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 u_int32_t outstandingQueueAIO(const PersistableQueue& queue) = 0;
+
+
+ virtual ~MessageStore(){}
+};
+
+}
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/MessageStoreModule.cpp b/qpid/cpp/src/qpid/broker/MessageStoreModule.cpp
new file mode 100644
index 0000000000..e02c87f069
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/MessageStoreModule.cpp
@@ -0,0 +1,147 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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 <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 namespace qpid::broker;
+using qpid::framing::FieldTable;
+
+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::recover(RecoveryManager& registry)
+{
+ TRANSFER_EXCEPTION(store->recover(registry));
+}
+
+void MessageStoreModule::stage( intrusive_ptr<PersistableMessage>& msg)
+{
+ TRANSFER_EXCEPTION(store->stage(msg));
+}
+
+void MessageStoreModule::destroy(PersistableMessage& msg)
+{
+ TRANSFER_EXCEPTION(store->destroy(msg));
+}
+
+void MessageStoreModule::appendContent(intrusive_ptr<const PersistableMessage>& msg, const std::string& data)
+{
+ TRANSFER_EXCEPTION(store->appendContent(msg, data));
+}
+
+void MessageStoreModule::loadContent(const qpid::broker::PersistableQueue& queue,
+ 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, intrusive_ptr<PersistableMessage>& msg, const PersistableQueue& queue)
+{
+ TRANSFER_EXCEPTION(store->enqueue(ctxt, msg, queue));
+}
+
+void MessageStoreModule::dequeue(TransactionContext* ctxt, 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));
+}
+
+u_int32_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));
+}
diff --git a/qpid/cpp/src/qpid/broker/MessageStoreModule.h b/qpid/cpp/src/qpid/broker/MessageStoreModule.h
new file mode 100644
index 0000000000..c7ad76d8bb
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/MessageStoreModule.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 _MessageStoreModule_
+#define _MessageStoreModule_
+
+#include "MessageStore.h"
+#include "Queue.h"
+#include "RecoveryManager.h"
+
+#include "qpid/sys/Module.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 recover(RecoveryManager& queues);
+ void stage(boost::intrusive_ptr<PersistableMessage>& msg);
+ void destroy(PersistableMessage& msg);
+ void appendContent(boost::intrusive_ptr<const PersistableMessage>& msg, const std::string& data);
+ void loadContent(const qpid::broker::PersistableQueue& queue,
+ boost::intrusive_ptr<const PersistableMessage>& msg, std::string& data,
+ uint64_t offset, uint32_t length);
+
+ void enqueue(TransactionContext* ctxt, boost::intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue& queue);
+ void dequeue(TransactionContext* ctxt, boost::intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue& queue);
+ u_int32_t outstandingQueueAIO(const PersistableQueue& queue);
+ void flush(const qpid::broker::PersistableQueue& queue);
+
+ ~MessageStoreModule();
+};
+
+}
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/NameGenerator.cpp b/qpid/cpp/src/qpid/broker/NameGenerator.cpp
new file mode 100644
index 0000000000..8484f921e9
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/broker/NameGenerator.h b/qpid/cpp/src/qpid/broker/NameGenerator.h
new file mode 100644
index 0000000000..6ea25c9797
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/broker/NullMessageStore.cpp b/qpid/cpp/src/qpid/broker/NullMessageStore.cpp
new file mode 100644
index 0000000000..8936b0440f
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/NullMessageStore.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 "NullMessageStore.h"
+#include "RecoveryManager.h"
+#include "qpid/log/Statement.h"
+
+#include <iostream>
+
+using boost::intrusive_ptr;
+
+namespace qpid{
+namespace broker{
+
+const std::string nullxid = "";
+
+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;
+ }
+};
+
+}
+}
+
+using namespace qpid::broker;
+
+NullMessageStore::NullMessageStore(bool _warn) : warn(_warn){}
+
+bool NullMessageStore::init(const Options* /*options*/) {return true;}
+
+void NullMessageStore::create(PersistableQueue& queue, const framing::FieldTable& /*args*/)
+{
+ QPID_LOG(info, "Queue '" << queue.getName()
+ << "' will not be durable. Persistence not enabled.");
+}
+
+void NullMessageStore::destroy(PersistableQueue&)
+{
+}
+
+void NullMessageStore::create(const PersistableExchange& exchange, const framing::FieldTable& /*args*/)
+{
+ QPID_LOG(info, "Exchange'" << exchange.getName()
+ << "' will not be durable. Persistence not enabled.");
+}
+
+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::recover(RecoveryManager&)
+{
+ QPID_LOG(info, "Persistence not enabled, no recovery attempted.");
+}
+
+void NullMessageStore::stage(intrusive_ptr<PersistableMessage>&)
+{
+ QPID_LOG(info, "Can't stage message. Persistence not enabled.");
+}
+
+void NullMessageStore::destroy(PersistableMessage&)
+{
+}
+
+void NullMessageStore::appendContent(intrusive_ptr<const PersistableMessage>&, const string&)
+{
+ QPID_LOG(info, "Can't append content. Persistence not enabled.");
+}
+
+void NullMessageStore::loadContent(const qpid::broker::PersistableQueue&, intrusive_ptr<const PersistableMessage>&, string&, uint64_t, uint32_t)
+{
+ QPID_LOG(info, "Can't load content. Persistence not enabled.");
+}
+
+void NullMessageStore::enqueue(TransactionContext*, intrusive_ptr<PersistableMessage>& msg, const PersistableQueue& queue)
+{
+ msg->enqueueComplete();
+ QPID_LOG(info, "Message is not durably recorded on '" << queue.getName() << "'. Persistence not enabled.");
+}
+
+void NullMessageStore::dequeue(TransactionContext*, intrusive_ptr<PersistableMessage>& msg, const PersistableQueue&)
+{
+ msg->dequeueComplete();
+}
+
+void NullMessageStore::flush(const qpid::broker::PersistableQueue&)
+{
+}
+
+u_int32_t NullMessageStore::outstandingQueueAIO(const PersistableQueue& )
+{
+ return 0;
+}
+
+std::auto_ptr<TransactionContext> NullMessageStore::begin()
+{
+ return std::auto_ptr<TransactionContext>();
+}
+
+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());
+}
diff --git a/qpid/cpp/src/qpid/broker/NullMessageStore.h b/qpid/cpp/src/qpid/broker/NullMessageStore.h
new file mode 100644
index 0000000000..96d1c483a2
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/NullMessageStore.h
@@ -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.
+ *
+ */
+#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;
+ const bool warn;
+public:
+ NullMessageStore(bool warn = false);
+
+ 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 recover(RecoveryManager& queues);
+ virtual void stage(boost::intrusive_ptr<PersistableMessage>& msg);
+ virtual void destroy(PersistableMessage& msg);
+ virtual void appendContent(boost::intrusive_ptr<const PersistableMessage>& msg,
+ const std::string& data);
+ virtual void loadContent(const qpid::broker::PersistableQueue& queue,
+ boost::intrusive_ptr<const PersistableMessage>& msg, std::string& data,
+ uint64_t offset, uint32_t length);
+ virtual void enqueue(TransactionContext* ctxt, boost::intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue& queue);
+ virtual void dequeue(TransactionContext* ctxt, boost::intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue& queue);
+ virtual u_int32_t outstandingQueueAIO(const PersistableQueue& queue);
+ virtual void flush(const qpid::broker::PersistableQueue& queue);
+ ~NullMessageStore(){}
+};
+
+}
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/OwnershipToken.h b/qpid/cpp/src/qpid/broker/OwnershipToken.h
new file mode 100644
index 0000000000..effd2f5b3c
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/broker/Persistable.h b/qpid/cpp/src/qpid/broker/Persistable.h
new file mode 100644
index 0000000000..36499c7a1a
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/broker/PersistableExchange.h b/qpid/cpp/src/qpid/broker/PersistableExchange.h
new file mode 100644
index 0000000000..683b740ddc
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/broker/PersistableMessage.cpp b/qpid/cpp/src/qpid/broker/PersistableMessage.cpp
new file mode 100644
index 0000000000..3bf390faf3
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/PersistableMessage.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 "PersistableMessage.h"
+#include "MessageStore.h"
+#include <iostream>
+
+using namespace qpid::broker;
+
+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);
+ }
+ }
+}
+
+
diff --git a/qpid/cpp/src/qpid/broker/PersistableMessage.h b/qpid/cpp/src/qpid/broker/PersistableMessage.h
new file mode 100644
index 0000000000..d5977665fe
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/PersistableMessage.h
@@ -0,0 +1,188 @@
+#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/Monitor.h"
+#include "PersistableQueue.h"
+
+namespace qpid {
+namespace broker {
+
+class MessageStore;
+
+/**
+ * The interface messages must expose to the MessageStore in order to
+ * be persistable.
+ */
+class PersistableMessage : public Persistable
+{
+ sys::Monitor asyncEnqueueLock;
+ sys::Monitor 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;
+protected:
+ typedef std::list< boost::weak_ptr<PersistableQueue> > syncList;
+ syncList synclist;
+ MessageStore* store;
+ bool contentReleased;
+
+ inline void setContentReleased() {contentReleased = true; }
+
+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():
+ asyncEnqueueCounter(0),
+ asyncDequeueCounter(0),
+ store(0),
+ contentReleased(false)
+ {}
+
+ void flush();
+
+ inline bool isContentReleased()const {return contentReleased; }
+
+ inline void waitForEnqueueComplete() {
+ sys::ScopedLock<sys::Monitor> l(asyncEnqueueLock);
+ while (asyncEnqueueCounter > 0) {
+ asyncEnqueueLock.wait();
+ }
+ }
+
+ inline bool isEnqueueComplete() {
+ sys::ScopedLock<sys::Monitor> l(asyncEnqueueLock);
+ return asyncEnqueueCounter == 0;
+ }
+
+ inline void enqueueComplete() {
+ bool notify = false;
+ {
+ sys::ScopedLock<sys::Monitor> l(asyncEnqueueLock);
+ if (asyncEnqueueCounter > 0) {
+ if (--asyncEnqueueCounter == 0) {
+ asyncEnqueueLock.notify();
+ notify = true;
+ }
+ }
+ }
+ if (notify) {
+ 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();
+ }
+ //synclist.clear();
+ }
+ }
+ }
+
+ inline void 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();
+ }
+
+ inline void enqueueAsync() {
+ sys::ScopedLock<sys::Monitor> l(asyncEnqueueLock);
+ asyncEnqueueCounter++;
+ }
+
+ inline bool isDequeueComplete() {
+ sys::ScopedLock<sys::Monitor> l(asyncDequeueLock);
+ return asyncDequeueCounter == 0;
+ }
+
+ inline void dequeueComplete() {
+
+ sys::ScopedLock<sys::Monitor> l(asyncDequeueLock);
+ if (asyncDequeueCounter > 0) {
+ if (--asyncDequeueCounter == 0) {
+ asyncDequeueLock.notify();
+ }
+ }
+ }
+
+ inline void waitForDequeueComplete() {
+ sys::ScopedLock<sys::Monitor> l(asyncDequeueLock);
+ while (asyncDequeueCounter > 0) {
+ asyncDequeueLock.wait();
+ }
+ }
+
+ inline void 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();
+ }
+
+ inline void dequeueAsync() {
+ sys::ScopedLock<sys::Monitor> l(asyncDequeueLock);
+ asyncDequeueCounter++;
+ }
+
+
+};
+
+}}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/PersistableQueue.h b/qpid/cpp/src/qpid/broker/PersistableQueue.h
new file mode 100644
index 0000000000..9236814ae3
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/broker/Prefetch.h b/qpid/cpp/src/qpid/broker/Prefetch.h
new file mode 100644
index 0000000000..8eb27a3e21
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/Prefetch.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.
+ *
+ */
+#ifndef _Prefetch_
+#define _Prefetch_
+
+#include "qpid/framing/amqp_types.h"
+
+namespace qpid {
+ namespace broker {
+ /**
+ * Count and total size of asynchronously delivered
+ * (i.e. pushed) messages that have acks outstanding.
+ */
+ struct Prefetch{
+ uint32_t size;
+ uint16_t count;
+
+ void reset() { size = 0; count = 0; }
+ };
+ }
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/PreviewConnection.cpp b/qpid/cpp/src/qpid/broker/PreviewConnection.cpp
new file mode 100644
index 0000000000..6f411c99d6
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/PreviewConnection.cpp
@@ -0,0 +1,341 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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 "PreviewConnection.h"
+#include "SessionState.h"
+#include "BrokerAdapter.h"
+#include "Bridge.h"
+#include "SemanticHandler.h"
+
+#include "qpid/log/Statement.h"
+#include "qpid/ptr_map.h"
+#include "qpid/framing/AMQP_ClientProxy.h"
+#include "qpid/management/ManagementAgent.h"
+
+#include <boost/bind.hpp>
+#include <boost/ptr_container/ptr_vector.hpp>
+
+#include <algorithm>
+#include <iostream>
+#include <assert.h>
+
+#if HAVE_SASL
+#include <sasl/sasl.h>
+#endif
+
+using namespace boost;
+using namespace qpid::sys;
+using namespace qpid::framing;
+using namespace qpid::sys;
+using namespace qpid::ptr_map;
+using qpid::management::ManagementAgent;
+using qpid::management::ManagementObject;
+using qpid::management::Manageable;
+using qpid::management::Args;
+
+namespace qpid {
+namespace broker {
+
+class PreviewConnection::MgmtClient : public PreviewConnection::MgmtWrapper
+{
+ management::Client::shared_ptr mgmtClient;
+
+public:
+ MgmtClient(PreviewConnection* conn, Manageable* parent, ManagementAgent::shared_ptr agent, const std::string& mgmtId);
+ ~MgmtClient();
+ void received(framing::AMQFrame& frame);
+ management::ManagementObject::shared_ptr getManagementObject() const;
+ void closing();
+};
+
+class PreviewConnection::MgmtLink : public PreviewConnection::MgmtWrapper
+{
+ typedef boost::ptr_vector<Bridge> Bridges;
+
+ management::Link::shared_ptr mgmtLink;
+ Bridges created;//holds list of bridges pending creation
+ Bridges cancelled;//holds list of bridges pending cancellation
+ Bridges active;//holds active bridges
+ uint channelCounter;
+ sys::Mutex linkLock;
+
+ void cancel(Bridge*);
+
+public:
+ MgmtLink(PreviewConnection* conn, Manageable* parent, ManagementAgent::shared_ptr agent, const std::string& mgmtId);
+ ~MgmtLink();
+ void received(framing::AMQFrame& frame);
+ management::ManagementObject::shared_ptr getManagementObject() const;
+ void closing();
+ void processPending();
+ void process(PreviewConnection& connection, const management::Args& args);
+};
+
+
+PreviewConnection::PreviewConnection(ConnectionOutputHandler* out_, Broker& broker_, const std::string& mgmtId_, bool isLink) :
+ ConnectionState(out_, broker_),
+#if HAVE_SASL
+ sasl_conn(NULL),
+#endif
+ adapter(*this, isLink),
+ mgmtClosing(false),
+ mgmtId(mgmtId_)
+{
+ Manageable* parent = broker.GetVhostObject ();
+
+ if (parent != 0)
+ {
+ ManagementAgent::shared_ptr agent = ManagementAgent::getAgent ();
+
+ if (agent.get () != 0)
+ {
+ if (isLink) {
+ mgmtWrapper = std::auto_ptr<MgmtWrapper>(new MgmtLink(this, parent, agent, mgmtId));
+ } else {
+ mgmtWrapper = std::auto_ptr<MgmtWrapper>(new MgmtClient(this, parent, agent, mgmtId));
+ }
+ }
+ }
+}
+
+PreviewConnection::~PreviewConnection () {
+#if HAVE_LIBSASL2
+ if (NULL != sasl_conn) {
+ sasl_dispose(&sasl_conn);
+ sasl_conn = NULL;
+ }
+#endif
+}
+
+void PreviewConnection::received(framing::AMQFrame& frame){
+ if (mgmtClosing)
+ close (403, "Closed by Management Request", 0, 0);
+
+ if (frame.getChannel() == 0) {
+ adapter.handle(frame);
+ } else {
+ getChannel(frame.getChannel()).in(frame);
+ }
+
+ if (mgmtWrapper.get()) mgmtWrapper->received(frame);
+}
+
+void PreviewConnection::close(
+ ReplyCode code, const string& text, ClassId classId, MethodId methodId)
+{
+ adapter.close(code, text, classId, methodId);
+ channels.clear();
+ getOutput().close();
+}
+
+void PreviewConnection::idleOut(){}
+
+void PreviewConnection::idleIn(){}
+
+void PreviewConnection::closed(){ // Physically closed, suspend open sessions.
+ try {
+ for (ChannelMap::iterator i = channels.begin(); i != channels.end(); ++i)
+ get_pointer(i)->localSuspend();
+ 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, " Unhandled exception while closing session: " <<
+ e.what());
+ assert(0);
+ }
+}
+
+bool PreviewConnection::doOutput()
+{
+ try{
+ //process any pending mgmt commands:
+ if (mgmtWrapper.get()) mgmtWrapper->processPending();
+ if (mgmtClosing) close (403, "Closed by Management Request", 0, 0);
+
+
+ //then do other output as needed:
+ return outputTasks.doOutput();
+ }catch(ConnectionException& e){
+ close(e.code, e.what(), 0, 0);
+ }catch(std::exception& e){
+ close(541/*internal error*/, e.what(), 0, 0);
+ }
+ return false;
+}
+
+void PreviewConnection::closeChannel(uint16_t id) {
+ ChannelMap::iterator i = channels.find(id);
+ if (i != channels.end()) channels.erase(i);
+}
+
+PreviewSessionHandler& PreviewConnection::getChannel(ChannelId id) {
+ ChannelMap::iterator i=channels.find(id);
+ if (i == channels.end()) {
+ i = channels.insert(id, new PreviewSessionHandler(*this, id)).first;
+ }
+ return *get_pointer(i);
+}
+
+ManagementObject::shared_ptr PreviewConnection::GetManagementObject (void) const
+{
+ return mgmtWrapper.get() ? mgmtWrapper->getManagementObject() : ManagementObject::shared_ptr();
+}
+
+Manageable::status_t PreviewConnection::ManagementMethod (uint32_t methodId,
+ Args& args)
+{
+ Manageable::status_t status = Manageable::STATUS_UNKNOWN_METHOD;
+
+ QPID_LOG (debug, "PreviewConnection::ManagementMethod [id=" << methodId << "]");
+
+ switch (methodId)
+ {
+ case management::Client::METHOD_CLOSE :
+ mgmtClosing = true;
+ if (mgmtWrapper.get()) mgmtWrapper->closing();
+ out->activateOutput();
+ status = Manageable::STATUS_OK;
+ break;
+ case management::Link::METHOD_BRIDGE :
+ //queue this up and request chance to do output (i.e. get connections thread of control):
+ mgmtWrapper->process(*this, args);
+ out->activateOutput();
+ status = Manageable::STATUS_OK;
+ break;
+ }
+
+ return status;
+}
+
+PreviewConnection::MgmtLink::MgmtLink(PreviewConnection* conn, Manageable* parent, ManagementAgent::shared_ptr agent, const std::string& mgmtId)
+ : channelCounter(1)
+{
+ mgmtLink = management::Link::shared_ptr
+ (new management::Link(conn, parent, mgmtId));
+ agent->addObject (mgmtLink);
+}
+
+PreviewConnection::MgmtLink::~MgmtLink()
+{
+ if (mgmtLink.get () != 0)
+ mgmtLink->resourceDestroy ();
+}
+
+void PreviewConnection::MgmtLink::received(framing::AMQFrame& frame)
+{
+ if (mgmtLink.get () != 0)
+ {
+ mgmtLink->inc_framesFromPeer ();
+ mgmtLink->inc_bytesFromPeer (frame.size ());
+ }
+}
+
+management::ManagementObject::shared_ptr PreviewConnection::MgmtLink::getManagementObject() const
+{
+ return dynamic_pointer_cast<ManagementObject>(mgmtLink);
+}
+
+void PreviewConnection::MgmtLink::closing()
+{
+ if (mgmtLink) mgmtLink->set_closing (1);
+}
+
+void PreviewConnection::MgmtLink::processPending()
+{
+ Mutex::ScopedLock l(linkLock);
+ //process any pending creates
+ if (!created.empty()) {
+ for (Bridges::iterator i = created.begin(); i != created.end(); ++i) {
+ i->create();
+ }
+ active.transfer(active.end(), created.begin(), created.end(), created);
+ }
+ if (!cancelled.empty()) {
+ //process any pending cancellations
+ for (Bridges::iterator i = cancelled.begin(); i != cancelled.end(); ++i) {
+ i->cancel();
+ }
+ cancelled.clear();
+ }
+}
+
+void PreviewConnection::MgmtLink::process(PreviewConnection& connection, const management::Args& args)
+{
+ Mutex::ScopedLock l(linkLock);
+ created.push_back(new Bridge(channelCounter++, connection,
+ boost::bind(&MgmtLink::cancel, this, _1),
+ dynamic_cast<const management::ArgsLinkBridge&>(args)));
+}
+
+void PreviewConnection::MgmtLink::cancel(Bridge* b)
+{
+ Mutex::ScopedLock l(linkLock);
+ //need to take this out the active map and add it to the cancelled map
+ for (Bridges::iterator i = active.begin(); i != active.end(); i++) {
+ if (&(*i) == b) {
+ cancelled.transfer(cancelled.end(), i, active);
+ break;
+ }
+ }
+}
+
+PreviewConnection::MgmtClient::MgmtClient(PreviewConnection* conn, Manageable* parent, ManagementAgent::shared_ptr agent, const std::string& mgmtId)
+{
+ mgmtClient = management::Client::shared_ptr
+ (new management::Client (conn, parent, mgmtId));
+ agent->addObject (mgmtClient);
+}
+
+PreviewConnection::MgmtClient::~MgmtClient()
+{
+ if (mgmtClient.get () != 0)
+ mgmtClient->resourceDestroy ();
+}
+
+void PreviewConnection::MgmtClient::received(framing::AMQFrame& frame)
+{
+ if (mgmtClient.get () != 0)
+ {
+ mgmtClient->inc_framesFromClient ();
+ mgmtClient->inc_bytesFromClient (frame.size ());
+ }
+}
+
+management::ManagementObject::shared_ptr PreviewConnection::MgmtClient::getManagementObject() const
+{
+ return dynamic_pointer_cast<ManagementObject>(mgmtClient);
+}
+
+void PreviewConnection::MgmtClient::closing()
+{
+ if (mgmtClient) mgmtClient->set_closing (1);
+}
+
+}}
+
diff --git a/qpid/cpp/src/qpid/broker/PreviewConnection.h b/qpid/cpp/src/qpid/broker/PreviewConnection.h
new file mode 100644
index 0000000000..c9e8b115d3
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/PreviewConnection.h
@@ -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.
+ *
+ */
+#ifndef _PreviewConnection_
+#define _PreviewConnection_
+
+#include "config.h"
+
+#include <memory>
+#include <sstream>
+#include <vector>
+
+#include <boost/ptr_container/ptr_map.hpp>
+
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/AMQP_ServerOperations.h"
+#include "qpid/framing/AMQP_ClientProxy.h"
+#include "qpid/sys/AggregateOutput.h"
+#include "qpid/sys/ConnectionOutputHandler.h"
+#include "qpid/sys/ConnectionInputHandler.h"
+#include "qpid/sys/TimeoutHandler.h"
+#include "qpid/framing/ProtocolVersion.h"
+#include "Broker.h"
+#include "qpid/sys/Socket.h"
+#include "qpid/Exception.h"
+#include "PreviewConnectionHandler.h"
+#include "ConnectionState.h"
+#include "PreviewSessionHandler.h"
+#include "qpid/management/Manageable.h"
+#include "qpid/management/Client.h"
+#include "qpid/management/Link.h"
+
+#include <boost/ptr_container/ptr_map.hpp>
+
+#if HAVE_SASL
+#include <sasl/sasl.h>
+#endif
+
+namespace qpid {
+namespace broker {
+
+class PreviewConnection : public sys::ConnectionInputHandler, public ConnectionState
+{
+#if HAVE_SASL
+ friend class PreviewConnectionHandler;
+#endif
+
+ public:
+ PreviewConnection(sys::ConnectionOutputHandler* out, Broker& broker, const std::string& mgmtId, bool isLink = false);
+ ~PreviewConnection ();
+
+ /** Get the PreviewSessionHandler for channel. Create if it does not already exist */
+ PreviewSessionHandler& getChannel(framing::ChannelId channel);
+
+ /** Close the connection */
+ void close(framing::ReplyCode code, const string& text, framing::ClassId classId, framing::MethodId methodId);
+
+ // ConnectionInputHandler methods
+ void received(framing::AMQFrame& frame);
+ void idleOut();
+ void idleIn();
+ void closed();
+ bool doOutput();
+
+ void closeChannel(framing::ChannelId channel);
+
+ // Manageable entry points
+ management::ManagementObject::shared_ptr GetManagementObject (void) const;
+ management::Manageable::status_t
+ ManagementMethod (uint32_t methodId, management::Args& args);
+
+ protected:
+#if HAVE_SASL
+ sasl_conn_t *sasl_conn;
+#endif
+
+ private:
+ typedef boost::ptr_map<framing::ChannelId, PreviewSessionHandler> ChannelMap;
+ typedef std::vector<Queue::shared_ptr>::iterator queue_iterator;
+
+ /**
+ * Connection may appear, for the purposes of management, as a
+ * normal client initiated connection or as an agent initiated
+ * inter-broker link. This wrapper abstracts the common interface
+ * for both.
+ */
+ class MgmtWrapper
+ {
+ public:
+ virtual ~MgmtWrapper(){}
+ virtual void received(framing::AMQFrame& frame) = 0;
+ virtual management::ManagementObject::shared_ptr getManagementObject() const = 0;
+ virtual void closing() = 0;
+ virtual void processPending(){}
+ virtual void process(PreviewConnection&, const management::Args&){}
+ };
+ class MgmtClient;
+ class MgmtLink;
+
+ ChannelMap channels;
+ framing::AMQP_ClientProxy::Connection* client;
+ uint64_t stagingThreshold;
+ PreviewConnectionHandler adapter;
+ std::auto_ptr<MgmtWrapper> mgmtWrapper;
+ bool mgmtClosing;
+ const std::string mgmtId;
+};
+
+}}
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/PreviewConnectionCodec.cpp b/qpid/cpp/src/qpid/broker/PreviewConnectionCodec.cpp
new file mode 100644
index 0000000000..b6c9b03776
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/PreviewConnectionCodec.cpp
@@ -0,0 +1,91 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "PreviewConnectionCodec.h"
+#include "qpid/log/Statement.h"
+
+namespace qpid {
+namespace broker {
+
+using sys::Mutex;
+
+PreviewConnectionCodec::PreviewConnectionCodec(sys::OutputControl& o, Broker& broker, const std::string& id, bool isClient)
+ : frameQueueClosed(false), output(o), connection(this, broker, id, isClient), identifier(id) {}
+
+size_t PreviewConnectionCodec::decode(const char* buffer, size_t size) {
+ framing::Buffer in(const_cast<char*>(buffer), size);
+ framing::AMQFrame frame;
+ while(frame.decode(in)) {
+ QPID_LOG(trace, "RECV [" << identifier << "]: " << frame);
+ connection.received(frame);
+ }
+ return in.getPosition();
+}
+
+bool PreviewConnectionCodec::canEncode() {
+ if (!frameQueueClosed && frameQueue.empty()) connection.doOutput();
+ return !frameQueue.empty();
+}
+
+bool PreviewConnectionCodec::isClosed() const {
+ Mutex::ScopedLock l(frameQueueLock);
+ return frameQueueClosed;
+}
+
+size_t PreviewConnectionCodec::encode(const char* buffer, size_t size) {
+ Mutex::ScopedLock l(frameQueueLock);
+ framing::Buffer out(const_cast<char*>(buffer), size);
+ while (!frameQueue.empty() && (frameQueue.front().size() <= out.available())) {
+ frameQueue.front().encode(out);
+ QPID_LOG(trace, "SENT [" << identifier << "]: " << frameQueue.front());
+ frameQueue.pop();
+ if (!frameQueueClosed && frameQueue.empty()) connection.doOutput();
+ }
+ if (!frameQueue.empty() && frameQueue.front().size() > size)
+ throw framing::ContentTooLargeException(QPID_MSG("Could not write frame, too large for buffer."));
+ return out.getPosition();
+}
+
+void PreviewConnectionCodec::activateOutput() { output.activateOutput(); }
+
+void PreviewConnectionCodec::close() {
+ // Close the output queue.
+ Mutex::ScopedLock l(frameQueueLock);
+ frameQueueClosed = true;
+}
+
+void PreviewConnectionCodec::closed() {
+ connection.closed();
+}
+
+void PreviewConnectionCodec::send(framing::AMQFrame& f) {
+ {
+ Mutex::ScopedLock l(frameQueueLock);
+ if (!frameQueueClosed)
+ frameQueue.push(f);
+ }
+ activateOutput();
+}
+
+framing::ProtocolVersion PreviewConnectionCodec::getVersion() const {
+ return framing::ProtocolVersion(99,0);
+}
+
+}} // namespace qpid::broker
diff --git a/qpid/cpp/src/qpid/broker/PreviewConnectionCodec.h b/qpid/cpp/src/qpid/broker/PreviewConnectionCodec.h
new file mode 100644
index 0000000000..f2ab086d06
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/PreviewConnectionCodec.h
@@ -0,0 +1,55 @@
+#ifndef QPID_BROKER_PREVIEWCONNECTIONCODEC_H
+#define QPID_BROKER_PREVIEWCONNECTIONCODEC_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/ConnectionOutputHandler.h"
+#include "qpid/sys/Mutex.h"
+#include "PreviewConnection.h"
+
+namespace qpid {
+namespace broker {
+
+class PreviewConnectionCodec : public sys::ConnectionCodec, public sys::ConnectionOutputHandler {
+ std::queue<framing::AMQFrame> frameQueue;
+ bool frameQueueClosed;
+ mutable sys::Mutex frameQueueLock;
+ sys::OutputControl& output;
+ PreviewConnection connection;
+ std::string identifier;
+
+ public:
+ PreviewConnectionCodec(sys::OutputControl&, Broker&, const std::string& id, bool isClient = false);
+ 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 closed(); // connection closed by peer.
+ void close(); // closing from this end.
+ void send(framing::AMQFrame&);
+ framing::ProtocolVersion getVersion() const;
+};
+
+}} // namespace qpid::broker
+
+#endif /*!QPID_BROKER_PREVIEWCONNECTIONCODEC_H*/
diff --git a/qpid/cpp/src/qpid/broker/PreviewConnectionHandler.cpp b/qpid/cpp/src/qpid/broker/PreviewConnectionHandler.cpp
new file mode 100644
index 0000000000..5c5f2f263e
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/PreviewConnectionHandler.cpp
@@ -0,0 +1,212 @@
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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 "PreviewConnectionHandler.h"
+#include "PreviewConnection.h"
+#include "qpid/framing/ConnectionStartBody.h"
+#include "qpid/framing/ClientInvoker.h"
+#include "qpid/framing/ServerInvoker.h"
+#include "qpid/log/Statement.h"
+
+#if HAVE_SASL
+#include <sasl/sasl.h>
+#endif
+
+using namespace qpid;
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+
+namespace
+{
+const std::string PLAIN = "PLAIN";
+const std::string en_US = "en_US";
+}
+
+void PreviewConnectionHandler::close(ReplyCode code, const string& text, ClassId classId, MethodId methodId)
+{
+ handler->client.close(code, text, classId, methodId);
+}
+
+void PreviewConnectionHandler::handle(framing::AMQFrame& frame)
+{
+ AMQMethodBody* method=frame.getBody()->getMethod();
+ try{
+ if (handler->serverMode) {
+ if (!invoke(static_cast<AMQP_ServerOperations::ConnectionHandler&>(*handler.get()), *method))
+ throw ChannelErrorException(QPID_MSG("Class can't be accessed over channel 0"));
+ } else {
+ if (!invoke(static_cast<AMQP_ClientOperations::ConnectionHandler&>(*handler.get()), *method))
+ throw ChannelErrorException(QPID_MSG("Class can't be accessed over channel 0"));
+ }
+ }catch(ConnectionException& e){
+ handler->client.close(e.code, e.what(), method->amqpClassId(), method->amqpMethodId());
+ }catch(std::exception& e){
+ handler->client.close(541/*internal error*/, e.what(), method->amqpClassId(), method->amqpMethodId());
+ }
+}
+
+PreviewConnectionHandler::PreviewConnectionHandler(PreviewConnection& connection, bool isClient) : handler(new Handler(connection)) {
+ FieldTable properties;
+ string mechanisms(PLAIN);
+ string locales(en_US);
+ if (isClient) {
+ handler->serverMode = false;
+ }else {
+ handler->serverMode = true;
+ handler->client.start(99, 0, properties, mechanisms, locales);
+ }
+}
+
+PreviewConnectionHandler::Handler:: Handler(PreviewConnection& c) : client(c.getOutput()), server(c.getOutput()),
+ connection(c), serverMode(false) {}
+
+void PreviewConnectionHandler::Handler::startOk(const framing::FieldTable& /*clientProperties*/,
+ const string& mechanism,
+ const string& response, const string& /*locale*/)
+{
+ //TODO: handle SASL mechanisms more cleverly
+ if (mechanism == PLAIN) {
+ QPID_LOG(info, "SASL Plain: Attempting authentication");
+ 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);
+
+#if HAVE_SASL
+ if (connection.getBroker().getOptions().auth) {
+ int code = sasl_server_new(BROKER_SASL_NAME,
+ NULL, NULL, NULL, NULL, NULL, 0,
+ &connection.sasl_conn);
+
+ if (SASL_OK != code) {
+ QPID_LOG(info, "SASL Plain: Connection creation failed: "
+ << sasl_errdetail(connection.sasl_conn));
+
+ // TODO: Change this to an exception signaling
+ // server error, when one is available
+ throw CommandInvalidException("Unable to perform authentication");
+ }
+
+ code = sasl_checkpass(connection.sasl_conn,
+ uid.c_str(), uid.length(),
+ pwd.c_str(), pwd.length());
+ if (SASL_OK == code) {
+ QPID_LOG(info, "SASL Plain: Authentication accepted for " << uid);
+ } else {
+ // See man sasl_errors(3) or sasl/sasl.h for possible errors
+ QPID_LOG(info, "SASL Plain: Authentication rejected for "
+ << uid << ": "
+ << sasl_errdetail(connection.sasl_conn));
+
+ // TODO: Change this to an exception signaling
+ // authentication failure, when one is available
+ throw ConnectionForcedException("Authentication failed");
+ }
+ } else {
+#endif
+ QPID_LOG(warning,
+ "SASL Plain Warning: No Authentication Performed for "
+ << uid);
+#if HAVE_SASL
+ }
+#endif
+
+ connection.setUserId(uid);
+ }
+ } else {
+ // The 0-10 spec states that if the client requests a
+ // mechanism not proposed by the server the server MUST
+ // close the connection. Assumption here is if we proposed
+ // a mechanism we'd have a case for it above.
+ throw NotImplementedException("Unsupported authentication mechanism");
+ }
+ client.tune(framing::CHANNEL_MAX, connection.getFrameMax(), connection.getHeartbeat());
+}
+
+void PreviewConnectionHandler::Handler::secureOk(const string& /*response*/){}
+
+void PreviewConnectionHandler::Handler::tuneOk(uint16_t /*channelmax*/,
+ uint32_t framemax, uint16_t heartbeat)
+{
+ connection.setFrameMax(framemax);
+ connection.setHeartbeat(heartbeat);
+}
+
+void PreviewConnectionHandler::Handler::open(const string& /*virtualHost*/,
+ const string& /*capabilities*/, bool /*insist*/)
+{
+ string knownhosts;
+ client.openOk(knownhosts);
+}
+
+
+void PreviewConnectionHandler::Handler::close(uint16_t /*replyCode*/, const string& /*replyText*/,
+ uint16_t /*classId*/, uint16_t /*methodId*/)
+{
+ client.closeOk();
+ connection.getOutput().close();
+}
+
+void PreviewConnectionHandler::Handler::closeOk(){
+ connection.getOutput().close();
+}
+
+
+void PreviewConnectionHandler::Handler::start(uint8_t /*versionMajor*/,
+ uint8_t /*versionMinor*/,
+ const FieldTable& /*serverProperties*/,
+ const string& /*mechanisms*/,
+ const string& /*locales*/)
+{
+ string uid = "qpidd";
+ string pwd = "qpidd";
+ string response = ((char)0) + uid + ((char)0) + pwd;
+ server.startOk(FieldTable(), PLAIN, response, en_US);
+}
+
+void PreviewConnectionHandler::Handler::secure(const string& /*challenge*/)
+{
+ server.secureOk("");
+}
+
+void PreviewConnectionHandler::Handler::tune(uint16_t channelMax,
+ uint32_t frameMax,
+ uint16_t heartbeat)
+{
+ connection.setFrameMax(frameMax);
+ connection.setHeartbeat(heartbeat);
+ server.tuneOk(channelMax, frameMax, heartbeat);
+ server.open("/", "", true);
+}
+
+void PreviewConnectionHandler::Handler::openOk(const string& /*knownHosts*/)
+{
+}
+
+void PreviewConnectionHandler::Handler::redirect(const string& /*host*/, const string& /*knownHosts*/)
+{
+
+}
diff --git a/qpid/cpp/src/qpid/broker/PreviewConnectionHandler.h b/qpid/cpp/src/qpid/broker/PreviewConnectionHandler.h
new file mode 100644
index 0000000000..7c3636373a
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/PreviewConnectionHandler.h
@@ -0,0 +1,91 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 _PreviewConnectionAdapter_
+#define _PreviewConnectionAdapter_
+
+#include <memory>
+#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/FrameHandler.h"
+#include "qpid/framing/ProtocolInitiation.h"
+#include "qpid/framing/ProtocolVersion.h"
+#include "qpid/Exception.h"
+
+namespace qpid {
+namespace broker {
+
+class PreviewConnection;
+
+// TODO aconway 2007-09-18: Rename to ConnectionHandler
+class PreviewConnectionHandler : 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;
+ PreviewConnection& connection;
+ bool serverMode;
+
+ Handler(PreviewConnection& connection);
+ 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, uint32_t frameMax, uint16_t heartbeat);
+ void open(const std::string& virtualHost,
+ const std::string& capabilities, bool insist);
+ void close(uint16_t replyCode, const std::string& replyText,
+ uint16_t classId, uint16_t methodId);
+ void closeOk();
+
+
+ void start(uint8_t versionMajor,
+ uint8_t versionMinor,
+ const qpid::framing::FieldTable& serverProperties,
+ const std::string& mechanisms,
+ const std::string& locales);
+
+ void secure(const std::string& challenge);
+
+ void tune(uint16_t channelMax,
+ uint32_t frameMax,
+ uint16_t heartbeat);
+
+ void openOk(const std::string& knownHosts);
+
+ void redirect(const std::string& host, const std::string& knownHosts);
+ };
+ std::auto_ptr<Handler> handler;
+ public:
+ PreviewConnectionHandler(PreviewConnection& connection, bool isClient);
+ void close(framing::ReplyCode code, const std::string& text, framing::ClassId classId, framing::MethodId methodId);
+ void handle(framing::AMQFrame& frame);
+};
+
+
+}}
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/PreviewSessionHandler.cpp b/qpid/cpp/src/qpid/broker/PreviewSessionHandler.cpp
new file mode 100644
index 0000000000..36092bb7f6
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/PreviewSessionHandler.cpp
@@ -0,0 +1,210 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "PreviewSessionHandler.h"
+#include "PreviewSessionState.h"
+#include "PreviewConnection.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/framing/constants.h"
+#include "qpid/framing/ClientInvoker.h"
+#include "qpid/framing/ServerInvoker.h"
+#include "qpid/log/Statement.h"
+
+#include <boost/bind.hpp>
+
+namespace qpid {
+namespace broker {
+using namespace framing;
+using namespace std;
+using namespace qpid::sys;
+
+PreviewSessionHandler::PreviewSessionHandler(PreviewConnection& c, ChannelId ch)
+ : InOutHandler(0, &out),
+ connection(c), channel(ch, &c.getOutput()),
+ proxy(out), // Via my own handleOut() for L2 data.
+ peerSession(channel), // Direct to channel for L2 commands.
+ ignoring(false) {}
+
+PreviewSessionHandler::~PreviewSessionHandler() {}
+
+namespace {
+ClassId classId(AMQMethodBody* m) { return m ? m->amqpMethodId() : 0; }
+MethodId methodId(AMQMethodBody* m) { return m ? m->amqpClassId() : 0; }
+} // namespace
+
+void PreviewSessionHandler::handleIn(AMQFrame& f) {
+ // Note on channel states: a channel is open if session != 0. A
+ // channel that is closed (session == 0) can be in the "ignoring"
+ // state. This is a temporary state after we have sent a channel
+ // exception, where extra frames might arrive that should be
+ // ignored.
+ //
+ AMQMethodBody* m = f.getBody()->getMethod();
+ try {
+ if (m && invoke(static_cast<AMQP_ServerOperations::SessionHandler&>(*this), *m)) {
+ return;
+ } else if (session.get()) {
+ boost::optional<SequenceNumber> ack=session->received(f);
+ session->in.handle(f);
+ if (ack)
+ peerSession.ack(*ack, SequenceNumberSet());
+ } else if (m && invoke(static_cast<AMQP_ClientOperations::SessionHandler&>(*this), *m)) {
+ return;
+ } else if (!ignoring) {
+ throw ChannelErrorException(
+ QPID_MSG("Channel " << channel.get() << " is not open"));
+ }
+ } catch(const ChannelException& e) {
+ ignoring=true; // Ignore trailing frames sent by client.
+ session->detach();
+ session.reset();
+ peerSession.closed(e.code, e.what());
+ }catch(const ConnectionException& e){
+ connection.close(e.code, e.what(), classId(m), methodId(m));
+ }catch(const std::exception& e){
+ connection.close(
+ framing::INTERNAL_ERROR, e.what(), classId(m), methodId(m));
+ }
+}
+
+void PreviewSessionHandler::handleOut(AMQFrame& f) {
+ channel.handle(f); // Send it.
+ if (session->sent(f))
+ peerSession.solicitAck();
+}
+
+void PreviewSessionHandler::assertAttached(const char* method) const {
+ if (!session.get())
+ throw ChannelErrorException(
+ QPID_MSG(method << " failed: No session for channel "
+ << getChannel()));
+}
+
+void PreviewSessionHandler::assertClosed(const char* method) const {
+ if (session.get())
+ throw ChannelBusyException(
+ QPID_MSG(method << " failed: channel " << channel.get()
+ << " is already open."));
+}
+
+void PreviewSessionHandler::open(uint32_t detachedLifetime) {
+ assertClosed("open");
+ std::auto_ptr<PreviewSessionState> state(
+ connection.broker.getPreviewSessionManager().open(*this, detachedLifetime));
+ session.reset(state.release());
+ peerSession.attached(session->getId(), session->getTimeout());
+}
+
+void PreviewSessionHandler::resume(const Uuid& id) {
+ assertClosed("resume");
+ session = connection.broker.getPreviewSessionManager().resume(id);
+ session->attach(*this);
+ SequenceNumber seq = session->resuming();
+ peerSession.attached(session->getId(), session->getTimeout());
+ proxy.getSession().ack(seq, SequenceNumberSet());
+}
+
+void PreviewSessionHandler::flow(bool /*active*/) {
+ assertAttached("flow");
+ // TODO aconway 2007-09-19: Removed in 0-10, remove
+ assert(0); throw NotImplementedException("session.flow");
+}
+
+void PreviewSessionHandler::flowOk(bool /*active*/) {
+ assertAttached("flowOk");
+ // TODO aconway 2007-09-19: Removed in 0-10, remove
+ assert(0); throw NotImplementedException("session.flowOk");
+}
+
+void PreviewSessionHandler::close() {
+ assertAttached("close");
+ QPID_LOG(info, "Received session.close");
+ ignoring=false;
+ session->detach();
+ session.reset();
+ peerSession.closed(REPLY_SUCCESS, "ok");
+ assert(&connection.getChannel(channel.get()) == this);
+ connection.closeChannel(channel.get());
+}
+
+void PreviewSessionHandler::closed(uint16_t replyCode, const string& replyText) {
+ QPID_LOG(warning, "Received session.closed: "<<replyCode<<" "<<replyText);
+ ignoring=false;
+ session->detach();
+ session.reset();
+}
+
+void PreviewSessionHandler::localSuspend() {
+ if (session.get() && session->isAttached()) {
+ session->detach();
+ connection.broker.getPreviewSessionManager().suspend(session);
+ session.reset();
+ }
+}
+
+void PreviewSessionHandler::suspend() {
+ assertAttached("suspend");
+ localSuspend();
+ peerSession.detached();
+ assert(&connection.getChannel(channel.get()) == this);
+ connection.closeChannel(channel.get());
+}
+
+void PreviewSessionHandler::ack(uint32_t cumulativeSeenMark,
+ const SequenceNumberSet& /*seenFrameSet*/)
+{
+ assertAttached("ack");
+ if (session->getState() == PreviewSessionState::RESUMING) {
+ session->receivedAck(cumulativeSeenMark);
+ framing::SessionState::Replay replay=session->replay();
+ std::for_each(replay.begin(), replay.end(),
+ boost::bind(&PreviewSessionHandler::handleOut, this, _1));
+ }
+ else
+ session->receivedAck(cumulativeSeenMark);
+}
+
+void PreviewSessionHandler::highWaterMark(uint32_t /*lastSentMark*/) {
+ // TODO aconway 2007-10-02: may be removed from spec.
+ assert(0); throw NotImplementedException("session.high-water-mark");
+}
+
+void PreviewSessionHandler::solicitAck() {
+ assertAttached("solicit-ack");
+ peerSession.ack(session->sendingAck(), SequenceNumberSet());
+}
+
+void PreviewSessionHandler::attached(const Uuid& /*sessionId*/, uint32_t detachedLifetime)
+{
+ std::auto_ptr<PreviewSessionState> state(
+ connection.broker.getPreviewSessionManager().open(*this, detachedLifetime));
+ session.reset(state.release());
+}
+
+void PreviewSessionHandler::detached()
+{
+ connection.broker.getPreviewSessionManager().suspend(session);
+ session.reset();
+}
+
+ConnectionState& PreviewSessionHandler::getConnection() { return connection; }
+const ConnectionState& PreviewSessionHandler::getConnection() const { return connection; }
+
+}} // namespace qpid::broker
diff --git a/qpid/cpp/src/qpid/broker/PreviewSessionHandler.h b/qpid/cpp/src/qpid/broker/PreviewSessionHandler.h
new file mode 100644
index 0000000000..4c517367d7
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/PreviewSessionHandler.h
@@ -0,0 +1,111 @@
+#ifndef QPID_BROKER_PREVIEWSESSIONHANDLER_H
+#define QPID_BROKER_PREVIEWSESSIONHANDLER_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_ClientOperations.h"
+#include "qpid/framing/AMQP_ServerOperations.h"
+#include "qpid/framing/AMQP_ClientProxy.h"
+#include "qpid/framing/amqp_types.h"
+#include "qpid/framing/ChannelHandler.h"
+#include "SessionContext.h"
+
+#include <boost/noncopyable.hpp>
+
+namespace qpid {
+namespace broker {
+
+class PreviewConnection;
+class PreviewSessionState;
+
+/**
+ * A SessionHandler is associated with each active channel. It
+ * receives incoming frames, handles session commands and manages the
+ * association between the channel and a session.
+ */
+class PreviewSessionHandler : public framing::AMQP_ServerOperations::SessionHandler,
+ public framing::AMQP_ClientOperations::SessionHandler,
+ public framing::FrameHandler::InOutHandler,
+ private boost::noncopyable
+{
+ public:
+ PreviewSessionHandler(PreviewConnection&, framing::ChannelId);
+ ~PreviewSessionHandler();
+
+ /** Returns 0 if not attached to a session */
+ PreviewSessionState* getSession() { return session.get(); }
+ const PreviewSessionState* getSession() const { return session.get(); }
+
+ framing::ChannelId getChannel() const { return channel.get(); }
+
+ ConnectionState& getConnection();
+ const ConnectionState& getConnection() const;
+
+ framing::AMQP_ClientProxy& getProxy() { return proxy; }
+ const framing::AMQP_ClientProxy& getProxy() const { return proxy; }
+
+ // Called by closing connection.
+ void localSuspend();
+ void detach() { localSuspend(); }
+
+ protected:
+ void handleIn(framing::AMQFrame&);
+ void handleOut(framing::AMQFrame&);
+
+ private:
+ /// Session methods
+ void open(uint32_t detachedLifetime);
+ void flow(bool active);
+ void flowOk(bool active);
+ void close();
+ void closed(uint16_t replyCode, const std::string& replyText);
+ void resume(const framing::Uuid& sessionId);
+ void suspend();
+ void ack(uint32_t cumulativeSeenMark,
+ const framing::SequenceNumberSet& seenFrameSet);
+ void highWaterMark(uint32_t lastSentMark);
+ void solicitAck();
+
+ //extra methods required for assuming client role
+ void attached(const framing::Uuid& sessionId, uint32_t detachedLifetime);
+ void detached();
+
+
+ void assertAttached(const char* method) const;
+ void assertActive(const char* method) const;
+ void assertClosed(const char* method) const;
+
+
+ PreviewConnection& connection;
+ framing::ChannelHandler channel;
+ framing::AMQP_ClientProxy proxy;
+ framing::AMQP_ClientProxy::Session peerSession;
+ bool ignoring;
+ std::auto_ptr<PreviewSessionState> session;
+};
+
+}} // namespace qpid::broker
+
+
+
+#endif /*!QPID_BROKER_SESSIONHANDLER_H*/
diff --git a/qpid/cpp/src/qpid/broker/PreviewSessionManager.cpp b/qpid/cpp/src/qpid/broker/PreviewSessionManager.cpp
new file mode 100644
index 0000000000..97a7c87e34
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/PreviewSessionManager.cpp
@@ -0,0 +1,113 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "PreviewSessionManager.h"
+#include "PreviewSessionState.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 <boost/intrusive_ptr.hpp>
+
+#include <algorithm>
+#include <functional>
+#include <ostream>
+
+namespace qpid {
+namespace broker {
+
+using namespace sys;
+using namespace framing;
+
+PreviewSessionManager::PreviewSessionManager(uint32_t a) : ack(a) {}
+
+PreviewSessionManager::~PreviewSessionManager() {}
+
+// FIXME aconway 2008-02-01: pass handler*, allow open unattached.
+std::auto_ptr<PreviewSessionState> PreviewSessionManager::open(
+ PreviewSessionHandler& h, uint32_t timeout_)
+{
+ Mutex::ScopedLock l(lock);
+ std::auto_ptr<PreviewSessionState> session(
+ new PreviewSessionState(this, &h, timeout_, ack));
+ active.insert(session->getId());
+ for_each(observers.begin(), observers.end(),
+ boost::bind(&Observer::opened, _1,boost::ref(*session)));
+ return session;
+}
+
+void PreviewSessionManager::suspend(std::auto_ptr<PreviewSessionState> session) {
+ Mutex::ScopedLock l(lock);
+ active.erase(session->getId());
+ session->suspend();
+ session->expiry = AbsTime(now(),session->getTimeout()*TIME_SEC);
+ if (session->mgmtObject.get() != 0)
+ session->mgmtObject->set_expireTime ((uint64_t) Duration (session->expiry));
+ suspended.push_back(session.release()); // In expiry order
+ eraseExpired();
+}
+
+std::auto_ptr<PreviewSessionState> PreviewSessionManager::resume(const Uuid& id)
+{
+ Mutex::ScopedLock l(lock);
+ eraseExpired();
+ if (active.find(id) != active.end())
+ throw SessionBusyException(
+ QPID_MSG("Session already active: " << id));
+ Suspended::iterator i = std::find_if(
+ suspended.begin(), suspended.end(),
+ boost::bind(std::equal_to<Uuid>(), id, boost::bind(&PreviewSessionState::getId, _1))
+ );
+ if (i == suspended.end())
+ throw InvalidArgumentException(
+ QPID_MSG("No suspended session with id=" << id));
+ active.insert(id);
+ std::auto_ptr<PreviewSessionState> state(suspended.release(i).release());
+ return state;
+}
+
+void PreviewSessionManager::erase(const framing::Uuid& id)
+{
+ Mutex::ScopedLock l(lock);
+ active.erase(id);
+}
+
+void PreviewSessionManager::eraseExpired() {
+ // Called with lock held.
+ if (!suspended.empty()) {
+ Suspended::iterator keep = std::lower_bound(
+ suspended.begin(), suspended.end(), now(),
+ boost::bind(std::less<AbsTime>(), boost::bind(&PreviewSessionState::expiry, _1), _2));
+ if (suspended.begin() != keep) {
+ QPID_LOG(debug, "Expiring sessions: " << log::formatList(suspended.begin(), keep));
+ suspended.erase(suspended.begin(), keep);
+ }
+ }
+}
+
+void PreviewSessionManager::add(const boost::intrusive_ptr<Observer>& o) {
+ observers.push_back(o);
+}
+
+}} // namespace qpid::broker
diff --git a/qpid/cpp/src/qpid/broker/PreviewSessionManager.h b/qpid/cpp/src/qpid/broker/PreviewSessionManager.h
new file mode 100644
index 0000000000..9bc6bc5bbc
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/PreviewSessionManager.h
@@ -0,0 +1,101 @@
+#ifndef QPID_BROKER_PREVIEWSESSIONMANAGER_H
+#define QPID_BROKER_PREVIEWSESSIONMANAGER_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/Uuid.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 PreviewSessionState;
+class PreviewSessionHandler;
+
+/**
+ * Create and manage PreviewSessionState objects.
+ */
+class PreviewSessionManager : private boost::noncopyable {
+ public:
+ /**
+ * Observer notified of PreviewSessionManager events.
+ */
+ struct Observer : public RefCounted {
+ virtual void opened(PreviewSessionState&) {}
+ };
+
+ PreviewSessionManager(uint32_t ack);
+
+ ~PreviewSessionManager();
+
+ /** Open a new active session, caller takes ownership */
+ std::auto_ptr<PreviewSessionState> open(PreviewSessionHandler& c, uint32_t timeout_);
+
+ /** Suspend a session, start it's timeout counter.
+ * The factory takes ownership.
+ */
+ void suspend(std::auto_ptr<PreviewSessionState> session);
+
+ /** Resume a suspended session.
+ *@throw Exception if timed out or non-existant.
+ */
+ std::auto_ptr<PreviewSessionState> resume(const framing::Uuid&);
+
+ /** Add an Observer. */
+ void add(const boost::intrusive_ptr<Observer>&);
+
+ private:
+ typedef boost::ptr_vector<PreviewSessionState> Suspended;
+ typedef std::set<framing::Uuid> Active;
+ typedef std::vector<boost::intrusive_ptr<Observer> > Observers;
+
+ void erase(const framing::Uuid&);
+ void eraseExpired();
+
+ sys::Mutex lock;
+ Suspended suspended;
+ Active active;
+ uint32_t ack;
+ Observers observers;
+
+ friend class PreviewSessionState; // removes deleted sessions from active set.
+};
+
+
+
+}} // namespace qpid::broker
+
+
+
+
+
+#endif /*!QPID_BROKER_PREVIEWSESSIONMANAGER_H*/
diff --git a/qpid/cpp/src/qpid/broker/PreviewSessionState.cpp b/qpid/cpp/src/qpid/broker/PreviewSessionState.cpp
new file mode 100644
index 0000000000..43c3b1509e
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/PreviewSessionState.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 "PreviewSessionState.h"
+#include "PreviewSessionManager.h"
+#include "PreviewSessionHandler.h"
+#include "ConnectionState.h"
+#include "Broker.h"
+#include "SemanticHandler.h"
+#include "qpid/framing/reply_exceptions.h"
+
+namespace qpid {
+namespace broker {
+
+using namespace framing;
+using sys::Mutex;
+using qpid::management::ManagementAgent;
+using qpid::management::ManagementObject;
+using qpid::management::Manageable;
+using qpid::management::Args;
+
+PreviewSessionState::PreviewSessionState(
+ PreviewSessionManager* f, PreviewSessionHandler* h, uint32_t timeout_, uint32_t ack)
+ : framing::SessionState(ack, timeout_ > 0),
+ factory(f), handler(h), id(true), timeout(timeout_),
+ broker(h->getConnection().broker),
+ version(h->getConnection().getVersion()),
+ semanticHandler(new SemanticHandler(*this))
+{
+ in.next = semanticHandler.get();
+ out.next = &handler->out;
+
+ getConnection().outputTasks.addOutputTask(&semanticHandler->getSemanticState());
+
+ Manageable* parent = broker.GetVhostObject ();
+
+ if (parent != 0)
+ {
+ ManagementAgent::shared_ptr agent = ManagementAgent::getAgent ();
+
+ if (agent.get () != 0)
+ {
+ mgmtObject = management::Session::shared_ptr
+ (new management::Session (this, parent, id.str ()));
+ mgmtObject->set_attached (1);
+ mgmtObject->set_clientRef (h->getConnection().GetManagementObject()->getObjectId());
+ mgmtObject->set_channelId (h->getChannel());
+ mgmtObject->set_detachedLifespan (getTimeout());
+ agent->addObject (mgmtObject);
+ }
+ }
+}
+
+PreviewSessionState::~PreviewSessionState() {
+ // Remove ID from active session list.
+ if (factory)
+ factory->erase(getId());
+ if (mgmtObject.get () != 0)
+ mgmtObject->resourceDestroy ();
+}
+
+PreviewSessionHandler* PreviewSessionState::getHandler() {
+ return handler;
+}
+
+AMQP_ClientProxy& PreviewSessionState::getProxy() {
+ assert(isAttached());
+ return getHandler()->getProxy();
+}
+
+ConnectionState& PreviewSessionState::getConnection() {
+ assert(isAttached());
+ return getHandler()->getConnection();
+}
+
+bool PreviewSessionState::isLocal(const ConnectionToken* t) const
+{
+ return isAttached() && &(handler->getConnection()) == t;
+}
+
+void PreviewSessionState::detach() {
+ getConnection().outputTasks.removeOutputTask(&semanticHandler->getSemanticState());
+ Mutex::ScopedLock l(lock);
+ handler = 0; out.next = 0;
+ if (mgmtObject.get() != 0)
+ {
+ mgmtObject->set_attached (0);
+ }
+}
+
+void PreviewSessionState::attach(PreviewSessionHandler& h) {
+ {
+ Mutex::ScopedLock l(lock);
+ handler = &h;
+ out.next = &handler->out;
+ if (mgmtObject.get() != 0)
+ {
+ mgmtObject->set_attached (1);
+ mgmtObject->set_clientRef (h.getConnection().GetManagementObject()->getObjectId());
+ mgmtObject->set_channelId (h.getChannel());
+ }
+ }
+ h.getConnection().outputTasks.addOutputTask(&semanticHandler->getSemanticState());
+}
+
+void PreviewSessionState::activateOutput()
+{
+ Mutex::ScopedLock l(lock);
+ if (isAttached()) {
+ getConnection().outputTasks.activateOutput();
+ }
+}
+ //This class could be used as the callback for queue notifications
+ //if not attached, it can simply ignore the callback, else pass it
+ //on to the connection
+
+ManagementObject::shared_ptr PreviewSessionState::GetManagementObject (void) const
+{
+ return dynamic_pointer_cast<ManagementObject> (mgmtObject);
+}
+
+Manageable::status_t PreviewSessionState::ManagementMethod (uint32_t methodId,
+ Args& /*args*/)
+{
+ Manageable::status_t status = Manageable::STATUS_UNKNOWN_METHOD;
+
+ switch (methodId)
+ {
+ case management::Session::METHOD_DETACH :
+ if (handler != 0)
+ {
+ handler->detach();
+ }
+ status = Manageable::STATUS_OK;
+ break;
+
+ case management::Session::METHOD_CLOSE :
+ /*
+ if (handler != 0)
+ {
+ handler->getConnection().closeChannel(handler->getChannel());
+ }
+ status = Manageable::STATUS_OK;
+ break;
+ */
+
+ case management::Session::METHOD_SOLICITACK :
+ case management::Session::METHOD_RESETLIFESPAN :
+ status = Manageable::STATUS_NOT_IMPLEMENTED;
+ break;
+ }
+
+ return status;
+}
+
+
+}} // namespace qpid::broker
diff --git a/qpid/cpp/src/qpid/broker/PreviewSessionState.h b/qpid/cpp/src/qpid/broker/PreviewSessionState.h
new file mode 100644
index 0000000000..1aecb12e72
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/PreviewSessionState.h
@@ -0,0 +1,125 @@
+#ifndef QPID_BROKER_PREVIEWSESSION_H
+#define QPID_BROKER_PREVIEWSESSION_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/Uuid.h"
+#include "qpid/framing/FrameHandler.h"
+#include "qpid/framing/SessionState.h"
+#include "qpid/framing/ProtocolVersion.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Time.h"
+#include "qpid/management/Manageable.h"
+#include "qpid/management/Session.h"
+#include "SessionContext.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 SemanticHandler;
+class PreviewSessionHandler;
+class PreviewSessionManager;
+class Broker;
+class ConnectionState;
+
+/**
+ * Broker-side session state includes sessions handler chains, which may
+ * themselves have state.
+ */
+class PreviewSessionState : public framing::SessionState,
+ public SessionContext,
+ public framing::FrameHandler::Chains,
+ public management::Manageable
+{
+ public:
+ ~PreviewSessionState();
+ bool isAttached() const { return handler; }
+
+ void detach();
+ void attach(PreviewSessionHandler& handler);
+
+
+ PreviewSessionHandler* getHandler();
+
+ /** @pre isAttached() */
+ framing::AMQP_ClientProxy& getProxy();
+
+ /** @pre isAttached() */
+ ConnectionState& getConnection();
+ bool isLocal(const ConnectionToken* t) const;
+
+ uint32_t getTimeout() const { return timeout; }
+ Broker& getBroker() { return broker; }
+ framing::ProtocolVersion getVersion() const { return version; }
+
+ /** OutputControl **/
+ void activateOutput();
+
+ // Manageable entry points
+ management::ManagementObject::shared_ptr GetManagementObject (void) const;
+ management::Manageable::status_t
+ ManagementMethod (uint32_t methodId, management::Args& args);
+
+ // Normally SessionManager creates sessions.
+ PreviewSessionState(PreviewSessionManager*,
+ PreviewSessionHandler* out,
+ uint32_t timeout,
+ uint32_t ackInterval);
+
+
+ private:
+ PreviewSessionManager* factory;
+ PreviewSessionHandler* handler;
+ framing::Uuid id;
+ uint32_t timeout;
+ sys::AbsTime expiry; // Used by SessionManager.
+ Broker& broker;
+ framing::ProtocolVersion version;
+ sys::Mutex lock;
+ boost::scoped_ptr<SemanticHandler> semanticHandler;
+ management::Session::shared_ptr mgmtObject;
+
+ friend class PreviewSessionManager;
+};
+
+
+inline std::ostream& operator<<(std::ostream& out, const PreviewSessionState& session) {
+ return out << session.getId();
+}
+
+}} // namespace qpid::broker
+
+
+
+#endif /*!QPID_BROKER_SESSION_H*/
diff --git a/qpid/cpp/src/qpid/broker/Queue.cpp b/qpid/cpp/src/qpid/broker/Queue.cpp
new file mode 100644
index 0000000000..591e9796d6
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/Queue.cpp
@@ -0,0 +1,661 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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 "QueueRegistry.h"
+
+#include "qpid/log/Statement.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/sys/Monitor.h"
+#include "qpid/sys/Time.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;
+
+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(false),
+ noLocal(false),
+ persistenceId(0)
+{
+ if (parent != 0)
+ {
+ ManagementAgent::shared_ptr agent = ManagementAgent::getAgent ();
+
+ if (agent.get () != 0)
+ {
+ mgmtObject = management::Queue::shared_ptr
+ (new management::Queue (this, parent, _name, _store != 0, _autodelete, 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.get () != 0)
+ mgmtObject->resourceDestroy ();
+}
+
+void Queue::notifyDurableIOComplete()
+{
+ Mutex::ScopedLock locker(messageLock);
+ notify();
+}
+
+bool Queue::isLocal(boost::intrusive_ptr<Message>& msg)
+{
+ return noLocal && owner && owner->isLocal(msg->getPublisher());
+}
+
+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(debug, "Dropping 'local' message from " << getName());
+ } else {
+ // if no store then mark as enqueued
+ if (!enqueue(0, msg)){
+ push(msg);
+ msg->enqueueComplete();
+ if (mgmtObject.get() != 0) {
+ mgmtObject->inc_msgTotalEnqueues ();
+ mgmtObject->inc_byteTotalEnqueues (msg->contentSize ());
+ mgmtObject->inc_msgDepth ();
+ mgmtObject->inc_byteDepth (msg->contentSize ());
+ }
+ }else {
+ if (mgmtObject.get() != 0) {
+ mgmtObject->inc_msgTotalEnqueues ();
+ mgmtObject->inc_byteTotalEnqueues (msg->contentSize ());
+ mgmtObject->inc_msgDepth ();
+ mgmtObject->inc_byteDepth (msg->contentSize ());
+ mgmtObject->inc_msgPersistEnqueues ();
+ mgmtObject->inc_bytePersistEnqueues (msg->contentSize ());
+ }
+ push(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
+ if (mgmtObject.get() != 0) {
+ mgmtObject->inc_msgTotalEnqueues ();
+ mgmtObject->inc_byteTotalEnqueues (msg->contentSize ());
+ mgmtObject->inc_msgPersistEnqueues ();
+ mgmtObject->inc_bytePersistEnqueues (msg->contentSize ());
+ mgmtObject->inc_msgDepth ();
+ mgmtObject->inc_byteDepth (msg->contentSize ());
+ }
+
+ 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);
+ if (mgmtObject.get() != 0) {
+ mgmtObject->inc_msgTotalEnqueues ();
+ mgmtObject->inc_byteTotalEnqueues (msg->contentSize ());
+ mgmtObject->inc_msgTxnEnqueues ();
+ mgmtObject->inc_byteTxnEnqueues (msg->contentSize ());
+ mgmtObject->inc_msgDepth ();
+ mgmtObject->inc_byteDepth (msg->contentSize ());
+ if (msg->isPersistent ()) {
+ mgmtObject->inc_msgPersistEnqueues ();
+ mgmtObject->inc_bytePersistEnqueues (msg->contentSize ());
+ }
+ }
+}
+
+void Queue::requeue(const QueuedMessage& msg){
+ Mutex::ScopedLock locker(messageLock);
+ msg.payload->enqueueComplete(); // mark the message as enqueued
+ messages.push_front(msg);
+ notify();
+}
+
+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) {
+ 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;
+}
+
+/**
+ * Return true if the message can be excluded. This is currently the
+ * case if the queue is exclusive and has an exclusive consumer that
+ * doesn't want the message or has a single consumer that doesn't want
+ * the message (covers the JMS topic case).
+ */
+bool Queue::canExcludeUnwanted()
+{
+ Mutex::ScopedLock locker(consumerLock);
+ return hasExclusiveOwner() && (exclusive || consumerCount == 1);
+}
+
+
+bool Queue::getNextMessage(QueuedMessage& m, Consumer& c)
+{
+ if (c.preAcquires()) {
+ return consumeNextMessage(m, c);
+ } else {
+ return browseNextMessage(m, c);
+ }
+}
+
+bool Queue::consumeNextMessage(QueuedMessage& m, Consumer& c)
+{
+ while (true) {
+ Mutex::ScopedLock locker(messageLock);
+ if (messages.empty()) {
+ QPID_LOG(debug, "No messages to dispatch on queue '" << name << "'");
+ addListener(c);
+ return false;
+ } else {
+ QueuedMessage msg = messages.front();
+ if (!msg.payload->isEnqueueComplete()) {
+ QPID_LOG(debug, "Messages not ready to dispatch on queue '" << name << "'");
+ addListener(c);
+ return false;
+ }
+
+ if (c.filter(msg.payload)) {
+ if (c.accept(msg.payload)) {
+ m = msg;
+ pop();
+ 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
+ if (canExcludeUnwanted()) {
+ //hack for no-local on JMS topics; get rid of this message
+ QPID_LOG(debug, "Excluding message from '" << name << "'");
+ pop();
+ } else {
+ //leave it for another consumer
+ QPID_LOG(debug, "Consumer doesn't want message from '" << name << "'");
+ return false;
+ }
+ }
+ }
+ }
+}
+
+
+bool Queue::browseNextMessage(QueuedMessage& m, Consumer& c)
+{
+ QueuedMessage msg(this);
+ while (seek(msg, c)) {
+ if (c.filter(msg.payload)) {
+ if (c.accept(msg.payload)) {
+ //consumer wants the message
+ c.position = msg.position;
+ m = msg;
+ 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::notify()
+{
+ //notify listeners that there may be messages to process
+ for_each(listeners.begin(), listeners.end(), mem_fun(&Consumer::notify));
+ listeners.clear();
+}
+
+void Queue::removeListener(Consumer& c)
+{
+ Mutex::ScopedLock locker(messageLock);
+ listeners.erase(&c);
+}
+
+void Queue::addListener(Consumer& c)
+{
+ listeners.insert(&c);
+}
+
+bool Queue::dispatch(Consumer& c)
+{
+ QueuedMessage msg(this);
+ if (getNextMessage(msg, c)) {
+ c.deliver(msg);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool Queue::seek(QueuedMessage& msg, Consumer& c) {
+ Mutex::ScopedLock locker(messageLock);
+ if (!messages.empty() && messages.back().position > c.position) {
+ if (c.position < messages.front().position) {
+ msg = messages.front();
+ 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;
+ }
+ }
+ addListener(c);
+ return false;
+}
+
+void Queue::consume(Consumer&, bool requestExclusive){
+ Mutex::ScopedLock locker(consumerLock);
+ if(exclusive) {
+ throw AccessRefusedException(
+ QPID_MSG("Queue " << getName() << " has an exclusive consumer. No more consumers allowed."));
+ } else if(requestExclusive) {
+ if(consumerCount) {
+ throw AccessRefusedException(
+ QPID_MSG("Queue " << getName() << " already has consumers. Exclusive access denied."));
+ } else {
+ exclusive = true;
+ }
+ }
+ consumerCount++;
+
+ if (mgmtObject.get() != 0){
+ mgmtObject->inc_consumers ();
+ }
+}
+
+void Queue::cancel(Consumer& c){
+ removeListener(c);
+ Mutex::ScopedLock locker(consumerLock);
+ consumerCount--;
+ if(exclusive) exclusive = false;
+ if (mgmtObject.get() != 0){
+ mgmtObject->dec_consumers ();
+ }
+}
+
+QueuedMessage Queue::dequeue(){
+ Mutex::ScopedLock locker(messageLock);
+ QueuedMessage msg(this);
+
+ if(!messages.empty()){
+ msg = messages.front();
+ pop();
+ }
+ return msg;
+}
+
+uint32_t Queue::purge(){
+ Mutex::ScopedLock locker(messageLock);
+ int count = messages.size();
+ while(!messages.empty()) pop();
+ return count;
+}
+
+/**
+ * Assumes messageLock is held
+ */
+void Queue::pop(){
+ QueuedMessage& msg = messages.front();
+
+ if (policy.get()) policy->dequeued(msg.payload->contentSize());
+ if (mgmtObject.get() != 0){
+ mgmtObject->inc_msgTotalDequeues ();
+ mgmtObject->inc_byteTotalDequeues (msg.payload->contentSize());
+ mgmtObject->dec_msgDepth ();
+ mgmtObject->dec_byteDepth (msg.payload->contentSize());
+ if (msg.payload->isPersistent ()){
+ mgmtObject->inc_msgPersistDequeues ();
+ mgmtObject->inc_bytePersistDequeues (msg.payload->contentSize());
+ }
+ }
+ messages.pop_front();
+}
+
+void Queue::push(boost::intrusive_ptr<Message>& msg){
+ Mutex::ScopedLock locker(messageLock);
+ messages.push_back(QueuedMessage(this, msg, ++sequence));
+ if (policy.get()) {
+ policy->enqueued(msg->contentSize());
+ if (policy->limitExceeded()) {
+ if (store) {
+ QPID_LOG(debug, "Message " << msg << " on " << name << " released from memory");
+ msg->releaseContent(store);
+ } else {
+ QPID_LOG(warning, "Message " << msg << " on " << name
+ << " exceeds the policy for the queue but can't be released from memory as the queue is not durable");
+ }
+ }
+ }
+ notify();
+}
+
+/** 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 ) {
+ 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;
+}
+
+// return true if store exists,
+bool Queue::enqueue(TransactionContext* ctxt, boost::intrusive_ptr<Message> msg)
+{
+ if (msg->isPersistent() && store) {
+ 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;
+ }
+ //msg->enqueueAsync(); // increments intrusive ptr cnt
+ return false;
+}
+
+// return true if store exists,
+bool Queue::dequeue(TransactionContext* ctxt, boost::intrusive_ptr<Message> msg)
+{
+ if (msg->isPersistent() && store) {
+ msg->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);
+ store->dequeue(ctxt, pmsg, *this);
+ return true;
+ }
+ //msg->dequeueAsync(); // decrements intrusive ptr cnt
+ return false;
+}
+
+
+namespace
+{
+ const std::string qpidMaxSize("qpid.max_size");
+ const std::string qpidMaxCount("qpid.max_count");
+ const std::string qpidNoLocal("no-local");
+}
+
+void Queue::create(const FieldTable& _settings)
+{
+ settings = _settings;
+ if (store) {
+ store->create(*this, _settings);
+ }
+ configure(_settings);
+}
+
+void Queue::configure(const FieldTable& _settings)
+{
+ std::auto_ptr<QueuePolicy> _policy(new QueuePolicy(_settings));
+ if (_policy->getMaxCount() || _policy->getMaxSize()) {
+ setPolicy(_policy);
+ }
+ if (owner) {
+ noLocal = _settings.get(qpidNoLocal);
+ QPID_LOG(debug, "Configured queue with no-local=" << noLocal);
+ }
+ if (mgmtObject.get() != 0)
+ mgmtObject->set_arguments (_settings);
+}
+
+void Queue::destroy()
+{
+ if (alternateExchange.get()) {
+ Mutex::ScopedLock locker(messageLock);
+ while(!messages.empty()){
+ DeliverableMessage msg(messages.front().payload);
+ alternateExchange->route(msg, msg.getMessage().getRoutingKey(),
+ msg.getMessage().getApplicationHeaders());
+ pop();
+ }
+ 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::shared_ptr agent = ManagementAgent::getAgent ();
+ agent->addObject (mgmtObject, _persistenceId);
+ }
+ persistenceId = _persistenceId;
+}
+
+void Queue::encode(framing::Buffer& buffer) const
+{
+ buffer.putShortString(name);
+ buffer.put(settings);
+}
+
+uint32_t Queue::encodedSize() const
+{
+ return name.size() + 1/*short string size octet*/ + settings.size();
+}
+
+Queue::shared_ptr Queue::decode(QueueRegistry& queues, framing::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);
+ 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::shared_ptr childObj = inst->GetManagementObject();
+ if (childObj.get() != 0)
+ mgmtObject->set_storeRef(childObj->getObjectId());
+ }
+}
+
+ManagementObject::shared_ptr Queue::GetManagementObject (void) const
+{
+ return dynamic_pointer_cast<ManagementObject> (mgmtObject);
+}
+
+Manageable::status_t Queue::ManagementMethod (uint32_t methodId,
+ Args& /*args*/)
+{
+ Manageable::status_t status = Manageable::STATUS_UNKNOWN_METHOD;
+
+ QPID_LOG (debug, "Queue::ManagementMethod [id=" << methodId << "]");
+
+ switch (methodId)
+ {
+ case management::Queue::METHOD_PURGE :
+ purge ();
+ status = Manageable::STATUS_OK;
+ break;
+ }
+
+ return status;
+}
diff --git a/qpid/cpp/src/qpid/broker/Queue.h b/qpid/cpp/src/qpid/broker/Queue.h
new file mode 100644
index 0000000000..8b92784b9a
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/Queue.h
@@ -0,0 +1,198 @@
+#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 "qpid/framing/FieldTable.h"
+#include "qpid/sys/Serializer.h"
+#include "qpid/sys/Monitor.h"
+#include "qpid/management/Manageable.h"
+#include "qpid/management/Queue.h"
+#include "qpid/framing/amqp_types.h"
+
+#include <vector>
+#include <memory>
+#include <deque>
+#include <set>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/intrusive_ptr.hpp>
+
+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::set<Consumer*> Listeners;
+ typedef std::deque<QueuedMessage> Messages;
+
+ const string name;
+ const bool autodelete;
+ MessageStore* store;
+ const OwnershipToken* owner;
+ uint32_t consumerCount;
+ bool exclusive;
+ bool noLocal;
+ Listeners listeners;
+ Messages messages;
+ 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;
+ QueueBindings bindings;
+ boost::shared_ptr<Exchange> alternateExchange;
+ framing::SequenceNumber sequence;
+ management::Queue::shared_ptr mgmtObject;
+
+ void pop();
+ void push(boost::intrusive_ptr<Message>& msg);
+ void setPolicy(std::auto_ptr<QueuePolicy> policy);
+ bool seek(QueuedMessage& msg, Consumer& position);
+ bool getNextMessage(QueuedMessage& msg, Consumer& c);
+ bool consumeNextMessage(QueuedMessage& msg, Consumer& c);
+ bool browseNextMessage(QueuedMessage& msg, Consumer& c);
+ bool canExcludeUnwanted();
+
+ void notify();
+ void removeListener(Consumer&);
+ void addListener(Consumer&);
+
+ 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&);
+
+ 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);
+
+ bool isLocal(boost::intrusive_ptr<Message>& 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& c, bool exclusive = false);
+ void cancel(Consumer& c);
+
+ uint32_t purge();
+ 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;
+
+ bool enqueue(TransactionContext* ctxt, boost::intrusive_ptr<Message> msg);
+ /**
+ * dequeue from store (only done once messages is acknowledged)
+ */
+ bool dequeue(TransactionContext* ctxt, boost::intrusive_ptr<Message> msg);
+ /**
+ * dequeues from memory only
+ */
+ QueuedMessage dequeue();
+
+ const QueuePolicy* getPolicy();
+
+ void setAlternateExchange(boost::shared_ptr<Exchange> exchange);
+ boost::shared_ptr<Exchange> getAlternateExchange();
+
+ //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::shared_ptr GetManagementObject (void) const;
+ management::Manageable::status_t
+ ManagementMethod (uint32_t methodId, management::Args& args);
+ };
+ }
+}
+
+
+#endif /*!_broker_Queue_h*/
diff --git a/qpid/cpp/src/qpid/broker/QueueBindings.cpp b/qpid/cpp/src/qpid/broker/QueueBindings.cpp
new file mode 100644
index 0000000000..e2fcd493db
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/QueueBindings.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 "QueueBindings.h"
+#include "ExchangeRegistry.h"
+
+using qpid::framing::FieldTable;
+using std::string;
+using namespace qpid::broker;
+
+void QueueBindings::add(const string& exchange, const string& key, const FieldTable& args)
+{
+ bindings.push_back(new Binding(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 (ChannelException&) {
+ }
+ }
+}
+
+QueueBindings::Binding::Binding(const string& _exchange, const string& _key, const FieldTable& _args)
+ : exchange(_exchange), key(_key), args(_args)
+{}
diff --git a/qpid/cpp/src/qpid/broker/QueueBindings.h b/qpid/cpp/src/qpid/broker/QueueBindings.h
new file mode 100644
index 0000000000..b9b0f7c15c
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/QueueBindings.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 _QueueBindings_
+#define _QueueBindings_
+
+#include "qpid/framing/FieldTable.h"
+#include <boost/ptr_container/ptr_list.hpp>
+#include <boost/shared_ptr.hpp>
+
+namespace qpid {
+namespace broker {
+
+class ExchangeRegistry;
+class Queue;
+class QueueBindings
+{
+ struct Binding{
+ const std::string exchange;
+ const std::string key;
+ const qpid::framing::FieldTable args;
+ Binding(const std::string& exchange, const std::string& key, const qpid::framing::FieldTable& args);
+ };
+
+ typedef boost::ptr_list<Binding> Bindings;
+ Bindings bindings;
+
+public:
+ void add(const std::string& exchange, const std::string& key, const qpid::framing::FieldTable& args);
+ void unbind(ExchangeRegistry& exchanges, boost::shared_ptr<Queue> queue);
+};
+
+
+}
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/QueuePolicy.cpp b/qpid/cpp/src/qpid/broker/QueuePolicy.cpp
new file mode 100644
index 0000000000..9b9717def0
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/QueuePolicy.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 "QueuePolicy.h"
+#include "qpid/framing/FieldValue.h"
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+QueuePolicy::QueuePolicy(uint32_t _maxCount, uint64_t _maxSize) :
+ maxCount(_maxCount), maxSize(_maxSize), count(0), size(0) {}
+
+QueuePolicy::QueuePolicy(const FieldTable& settings) :
+ maxCount(getInt(settings, maxCountKey, 0)),
+ maxSize(getInt(settings, maxSizeKey, 0)), count(0), size(0) {}
+
+void QueuePolicy::enqueued(uint64_t _size)
+{
+ if (maxCount) count++;
+ if (maxSize) size += _size;
+}
+
+void QueuePolicy::dequeued(uint64_t _size)
+{
+ if (maxCount) count--;
+ if (maxSize) size -= _size;
+}
+
+bool QueuePolicy::limitExceeded()
+{
+ return (maxSize && size > maxSize) || (maxCount && count > maxCount);
+}
+
+void QueuePolicy::update(FieldTable& settings)
+{
+ if (maxCount) settings.setInt(maxCountKey, maxCount);
+ if (maxSize) settings.setInt(maxSizeKey, maxSize);
+}
+
+
+int QueuePolicy::getInt(const FieldTable& settings, const std::string& key, int defaultValue)
+{
+ //Note: currently field table only contain signed 32 bit ints, which
+ // restricts the values that can be set on the queue policy.
+ try {
+ return settings.getInt(key);
+ } catch (FieldValueException& ignore) {
+ return defaultValue;
+ }
+}
+
+const std::string QueuePolicy::maxCountKey("qpid.max_count");
+const std::string QueuePolicy::maxSizeKey("qpid.max_size");
diff --git a/qpid/cpp/src/qpid/broker/QueuePolicy.h b/qpid/cpp/src/qpid/broker/QueuePolicy.h
new file mode 100644
index 0000000000..0cc7070e09
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/QueuePolicy.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 _QueuePolicy_
+#define _QueuePolicy_
+
+#include "qpid/framing/FieldTable.h"
+
+namespace qpid {
+ namespace broker {
+ class QueuePolicy
+ {
+ static const std::string maxCountKey;
+ static const std::string maxSizeKey;
+
+ const uint32_t maxCount;
+ const uint64_t maxSize;
+ uint32_t count;
+ uint64_t size;
+
+ static int getInt(const qpid::framing::FieldTable& settings, const std::string& key, int defaultValue);
+
+ public:
+ QueuePolicy(uint32_t maxCount, uint64_t maxSize);
+ QueuePolicy(const qpid::framing::FieldTable& settings);
+ void enqueued(uint64_t size);
+ void dequeued(uint64_t size);
+ void update(qpid::framing::FieldTable& settings);
+ bool limitExceeded();
+ uint32_t getMaxCount() const { return maxCount; }
+ uint64_t getMaxSize() const { return maxSize; }
+ };
+ }
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/QueueRegistry.cpp b/qpid/cpp/src/qpid/broker/QueueRegistry.cpp
new file mode 100644
index 0000000000..61bdb0ffde
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/QueueRegistry.cpp
@@ -0,0 +1,93 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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) {}
+
+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;
+
+ 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)
+{
+ assert (store == 0 && _store != 0);
+ store = _store;
+}
+
+MessageStore* QueueRegistry::getStore() const {
+ return store;
+}
diff --git a/qpid/cpp/src/qpid/broker/QueueRegistry.h b/qpid/cpp/src/qpid/broker/QueueRegistry.h
new file mode 100644
index 0000000000..60da0619f4
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/QueueRegistry.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 _QueueRegistry_
+#define _QueueRegistry_
+
+#include <map>
+#include "qpid/sys/Mutex.h"
+#include "Queue.h"
+#include "qpid/management/Manageable.h"
+
+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* const 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; }
+
+private:
+ typedef std::map<string, Queue::shared_ptr> QueueMap;
+ QueueMap queues;
+ qpid::sys::RWlock lock;
+ int counter;
+ MessageStore* store;
+ management::Manageable* parent;
+
+ //destroy impl that assumes lock is already held:
+ void destroyLH (const string& name);
+};
+
+
+}
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/RecoverableExchange.h b/qpid/cpp/src/qpid/broker/RecoverableExchange.h
new file mode 100644
index 0000000000..76d0d2ecdf
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/broker/RecoverableMessage.h b/qpid/cpp/src/qpid/broker/RecoverableMessage.h
new file mode 100644
index 0000000000..f755fdf727
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/broker/RecoverableQueue.h b/qpid/cpp/src/qpid/broker/RecoverableQueue.h
new file mode 100644
index 0000000000..b32bae7f07
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/broker/RecoverableTransaction.h b/qpid/cpp/src/qpid/broker/RecoverableTransaction.h
new file mode 100644
index 0000000000..7fe34b6756
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/broker/RecoveredDequeue.cpp b/qpid/cpp/src/qpid/broker/RecoveredDequeue.cpp
new file mode 100644
index 0000000000..e2d70964fb
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/broker/RecoveredDequeue.h b/qpid/cpp/src/qpid/broker/RecoveredDequeue.h
new file mode 100644
index 0000000000..276e1f4c5c
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/RecoveredDequeue.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 _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(){}
+ };
+ }
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/RecoveredEnqueue.cpp b/qpid/cpp/src/qpid/broker/RecoveredEnqueue.cpp
new file mode 100644
index 0000000000..1984a5d4a8
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/broker/RecoveredEnqueue.h b/qpid/cpp/src/qpid/broker/RecoveredEnqueue.h
new file mode 100644
index 0000000000..6525179769
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/RecoveredEnqueue.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 _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(){}
+ };
+ }
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/RecoveryManager.h b/qpid/cpp/src/qpid/broker/RecoveryManager.h
new file mode 100644
index 0000000000..bf1813a093
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/RecoveryManager.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 _RecoveryManager_
+#define _RecoveryManager_
+
+#include "RecoverableExchange.h"
+#include "RecoverableQueue.h"
+#include "RecoverableMessage.h"
+#include "RecoverableTransaction.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 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/qpid/cpp/src/qpid/broker/RecoveryManagerImpl.cpp b/qpid/cpp/src/qpid/broker/RecoveryManagerImpl.cpp
new file mode 100644
index 0000000000..97226ebc22
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/RecoveryManagerImpl.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 "RecoveryManagerImpl.h"
+
+#include "Message.h"
+#include "Queue.h"
+#include "RecoveredEnqueue.h"
+#include "RecoveredDequeue.h"
+
+using namespace qpid;
+using namespace qpid::broker;
+using boost::dynamic_pointer_cast;
+using boost::intrusive_ptr;
+
+static const uint8_t BASIC = 1;
+static const uint8_t MESSAGE = 2;
+
+RecoveryManagerImpl::RecoveryManagerImpl(QueueRegistry& _queues, ExchangeRegistry& _exchanges,
+ DtxManager& _dtxMgr, uint64_t _stagingThreshold)
+ : queues(_queues), exchanges(_exchanges), dtxMgr(_dtxMgr), stagingThreshold(_stagingThreshold) {}
+
+RecoveryManagerImpl::~RecoveryManagerImpl() {}
+
+class RecoverableMessageImpl : public RecoverableMessage
+{
+ intrusive_ptr<Message> msg;
+ const uint64_t stagingThreshold;
+public:
+ RecoverableMessageImpl(Message::shared_ptr& _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(Queue::shared_ptr& _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 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 (ChannelException& e) {
+ //assume no default exchange has been declared
+ }
+ return RecoverableQueue::shared_ptr(new RecoverableQueueImpl(queue));
+}
+
+RecoverableMessage::shared_ptr RecoveryManagerImpl::recoverMessage(framing::Buffer& buffer)
+{
+ Message::shared_ptr 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));
+}
+
+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 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/qpid/cpp/src/qpid/broker/RecoveryManagerImpl.h b/qpid/cpp/src/qpid/broker/RecoveryManagerImpl.h
new file mode 100644
index 0000000000..58ec63926c
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/RecoveryManagerImpl.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 _RecoveryManagerImpl_
+#define _RecoveryManagerImpl_
+
+#include <list>
+#include "DtxManager.h"
+#include "ExchangeRegistry.h"
+#include "QueueRegistry.h"
+#include "RecoveryManager.h"
+
+namespace qpid {
+namespace broker {
+
+ class RecoveryManagerImpl : public RecoveryManager{
+ QueueRegistry& queues;
+ ExchangeRegistry& exchanges;
+ DtxManager& dtxMgr;
+ const uint64_t stagingThreshold;
+ public:
+ RecoveryManagerImpl(QueueRegistry& queues, ExchangeRegistry& exchanges, 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);
+ void recoveryComplete();
+ };
+
+
+}
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/SemanticHandler.cpp b/qpid/cpp/src/qpid/broker/SemanticHandler.cpp
new file mode 100644
index 0000000000..eb45ff1492
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/SemanticHandler.cpp
@@ -0,0 +1,196 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "SemanticHandler.h"
+#include "SemanticState.h"
+#include "SessionContext.h"
+#include "BrokerAdapter.h"
+#include "MessageDelivery.h"
+#include "qpid/framing/ExecutionCompleteBody.h"
+#include "qpid/framing/ExecutionResultBody.h"
+#include "qpid/framing/ServerInvoker.h"
+#include "qpid/log/Statement.h"
+
+#include <boost/format.hpp>
+#include <boost/bind.hpp>
+
+using boost::intrusive_ptr;
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+SemanticHandler::SemanticHandler(SessionContext& s) :
+ state(*this,s), session(s),
+ msgBuilder(&s.getConnection().getBroker().getStore(), s.getConnection().getBroker().getStagingThreshold()),
+ ackOp(boost::bind(&SemanticState::ackRange, &state, _1, _2))
+ {}
+
+void SemanticHandler::handle(framing::AMQFrame& frame)
+{
+ //TODO: assembly for method and headers
+
+ //have potentially three separate tracks at this point:
+ //
+ // (1) execution controls
+ // (2) commands
+ // (3) data i.e. content-bearing commands
+ //
+ //framesets on each can be interleaved. framesets on the latter
+ //two share a command-id sequence. controls on the first track are
+ //used to communicate details about that command-id sequence.
+ //
+ //need to decide what to do if a frame on the command track
+ //arrives while a frameset on the data track is still
+ //open. execute it (i.e. out-of order execution with respect to
+ //the command id sequence) or queue it up?
+
+ TrackId track = getTrack(frame);//will be replaced by field in 0-10 frame header
+
+ switch(track) {
+ case EXECUTION_CONTROL_TRACK:
+ handleL3(frame.getMethod());
+ break;
+ case MODEL_COMMAND_TRACK:
+ handleCommand(frame.getMethod());
+ break;
+ case MODEL_CONTENT_TRACK:
+ handleContent(frame);
+ break;
+ }
+}
+
+void SemanticHandler::complete(uint32_t cumulative, const SequenceNumberSet& range)
+{
+ //record:
+ SequenceNumber mark(cumulative);
+ if (outgoing.lwm < mark) {
+ outgoing.lwm = mark;
+ //ack messages:
+ state.ackCumulative(mark.getValue());
+ }
+ range.processRanges(ackOp);
+}
+
+void SemanticHandler::sendCompletion()
+{
+ SequenceNumber mark = incoming.getMark();
+ SequenceNumberSet range = incoming.getRange();
+ session.getProxy().getExecution().complete(mark.getValue(), range);
+}
+
+void SemanticHandler::flush()
+{
+ incoming.flush();
+ sendCompletion();
+}
+void SemanticHandler::sync()
+{
+ incoming.sync();
+ sendCompletion();
+}
+
+void SemanticHandler::noop()
+{
+ incoming.noop();
+}
+
+void SemanticHandler::result(uint32_t /*command*/, const std::string& /*data*/)
+{
+ //never actually sent by client at present
+}
+
+void SemanticHandler::handleCommand(framing::AMQMethodBody* method)
+{
+ SequenceNumber id = incoming.next();
+ BrokerAdapter adapter(state);
+ Invoker::Result invoker = invoke(adapter, *method);
+ incoming.complete(id);
+
+ if (!invoker.wasHandled()) {
+ throw NotImplementedException("Not implemented");
+ } else if (invoker.hasResult()) {
+ session.getProxy().getExecution().result(id.getValue(), invoker.getResult());
+ }
+ if (method->isSync()) {
+ incoming.sync(id);
+ sendCompletion();
+ }
+ //TODO: if window gets too large send unsolicited completion
+}
+
+void SemanticHandler::handleL3(framing::AMQMethodBody* method)
+{
+ if (!invoke(*this, *method))
+ throw NotImplementedException("Not implemented");
+}
+
+void SemanticHandler::handleContent(AMQFrame& frame)
+{
+ intrusive_ptr<Message> msg(msgBuilder.getMessage());
+ if (!msg) {//start of frameset will be indicated by frame flags
+ msgBuilder.start(incoming.next());
+ msg = msgBuilder.getMessage();
+ }
+ msgBuilder.handle(frame);
+ if (frame.getEof() && frame.getEos()) {//end of frameset will be indicated by frame flags
+ msg->setPublisher(&session.getConnection());
+ state.handle(msg);
+ msgBuilder.end();
+ incoming.track(msg);
+ if (msg->getFrames().getMethod()->isSync()) {
+ incoming.sync(msg->getCommandId());
+ sendCompletion();
+ }
+ }
+}
+
+DeliveryId SemanticHandler::deliver(QueuedMessage& msg, DeliveryToken::shared_ptr token)
+{
+ uint32_t maxFrameSize = session.getConnection().getFrameMax();
+ MessageDelivery::deliver(msg, session.getProxy().getHandler(), ++outgoing.hwm, token, maxFrameSize);
+ return outgoing.hwm;
+}
+
+SemanticHandler::TrackId SemanticHandler::getTrack(const AMQFrame& frame)
+{
+ //will be replaced by field in 0-10 frame header
+ uint8_t type = frame.getBody()->type();
+ uint16_t classId;
+ switch(type) {
+ case METHOD_BODY:
+ if (frame.castBody<AMQMethodBody>()->isContentBearing()) {
+ return MODEL_CONTENT_TRACK;
+ }
+
+ classId = frame.castBody<AMQMethodBody>()->amqpClassId();
+ switch (classId) {
+ case ExecutionCompleteBody::CLASS_ID:
+ return EXECUTION_CONTROL_TRACK;
+ }
+
+ return MODEL_COMMAND_TRACK;
+ case HEADER_BODY:
+ case CONTENT_BODY:
+ return MODEL_CONTENT_TRACK;
+ }
+ throw Exception("Could not determine track");
+}
+
diff --git a/qpid/cpp/src/qpid/broker/SemanticHandler.h b/qpid/cpp/src/qpid/broker/SemanticHandler.h
new file mode 100644
index 0000000000..893a0cbded
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/SemanticHandler.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.
+ *
+ */
+#ifndef _SemanticHandler_
+#define _SemanticHandler_
+
+#include <memory>
+#include "BrokerAdapter.h"
+#include "DeliveryAdapter.h"
+#include "MessageBuilder.h"
+#include "IncomingExecutionContext.h"
+#include "HandlerImpl.h"
+
+#include "qpid/framing/amqp_types.h"
+#include "qpid/framing/AMQP_ServerOperations.h"
+#include "qpid/framing/FrameHandler.h"
+#include "qpid/framing/SequenceNumber.h"
+
+#include <boost/function.hpp>
+
+namespace qpid {
+
+namespace framing {
+class AMQMethodBody;
+class AMQHeaderBody;
+class AMQContentBody;
+class AMQHeaderBody;
+}
+
+namespace broker {
+
+class SessionContext;
+
+class SemanticHandler : public DeliveryAdapter,
+ public framing::FrameHandler,
+ public framing::AMQP_ServerOperations::ExecutionHandler
+
+{
+ typedef boost::function<void(DeliveryId, DeliveryId)> RangedOperation;
+
+ SemanticState state;
+ SessionContext& session;
+ // TODO aconway 2007-09-20: Why are these on the handler rather than the
+ // state?
+ IncomingExecutionContext incoming;
+ framing::Window outgoing;
+ MessageBuilder msgBuilder;
+ RangedOperation ackOp;
+
+ enum TrackId {EXECUTION_CONTROL_TRACK, MODEL_COMMAND_TRACK, MODEL_CONTENT_TRACK};
+ TrackId getTrack(const framing::AMQFrame& frame);
+
+ void handleL3(framing::AMQMethodBody* method);
+ void handleCommand(framing::AMQMethodBody* method);
+ void handleContent(framing::AMQFrame& frame);
+
+ void sendCompletion();
+
+ //delivery adapter methods:
+ DeliveryId deliver(QueuedMessage& msg, DeliveryToken::shared_ptr token);
+
+ framing::AMQP_ClientProxy& getProxy() { return session.getProxy(); }
+ //Connection& getConnection() { return session.getConnection(); }
+ Broker& getBroker() { return session.getConnection().getBroker(); }
+
+public:
+ SemanticHandler(SessionContext& session);
+
+ //frame handler:
+ void handle(framing::AMQFrame& frame);
+
+ //execution class method handlers:
+ void complete(uint32_t cumulativeExecutionMark, const framing::SequenceNumberSet& range);
+ void flush();
+ void noop();
+ void result(uint32_t command, const std::string& data);
+ void sync();
+
+
+ SemanticState& getSemanticState() { return state; }
+};
+
+}}
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/SemanticState.cpp b/qpid/cpp/src/qpid/broker/SemanticState.cpp
new file mode 100644
index 0000000000..2251901340
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/SemanticState.cpp
@@ -0,0 +1,696 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "SessionContext.h"
+#include "BrokerAdapter.h"
+#include "Queue.h"
+#include "Connection.h"
+#include "DeliverableMessage.h"
+#include "DtxAck.h"
+#include "DtxTimeout.h"
+#include "Message.h"
+#include "SemanticHandler.h"
+#include "SessionHandler.h"
+#include "TxAccept.h"
+#include "TxAck.h"
+#include "TxPublish.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/framing/Message010TransferBody.h"
+#include "qpid/log/Statement.h"
+#include "qpid/ptr_map.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 std::bind2nd;
+using boost::intrusive_ptr;
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::sys;
+using namespace qpid::ptr_map;
+
+SemanticState::SemanticState(DeliveryAdapter& da, SessionContext& ss)
+ : session(ss),
+ deliveryAdapter(da),
+ prefetchSize(0),
+ prefetchCount(0),
+ tagGenerator("sgen"),
+ dtxSelected(false),
+ accumulatedAck(0),
+ flowActive(true),
+ outputTasks(ss)
+{
+ outstanding.reset();
+}
+
+SemanticState::~SemanticState() {
+ //cancel all consumers
+ for (ConsumerImplMap::iterator i = consumers.begin(); i != consumers.end(); i++) {
+ cancel(*get_pointer(i));
+ }
+
+ if (dtxBuffer.get()) {
+ dtxBuffer->fail();
+ }
+ recover(true);
+}
+
+bool SemanticState::exists(const string& consumerTag){
+ return consumers.find(consumerTag) != consumers.end();
+}
+
+void SemanticState::consume(DeliveryToken::shared_ptr token, string& tagInOut,
+ Queue::shared_ptr queue, bool nolocal, bool ackRequired, bool acquire,
+ bool exclusive, const FieldTable*)
+{
+ if(tagInOut.empty())
+ tagInOut = tagGenerator.generate();
+ std::auto_ptr<ConsumerImpl> c(new ConsumerImpl(this, token, tagInOut, queue, ackRequired, nolocal, acquire));
+ queue->consume(*c, exclusive);//may throw exception
+ outputTasks.addOutputTask(c.get());
+ consumers.insert(tagInOut, c.release());
+}
+
+void SemanticState::cancel(const string& tag){
+ ConsumerImplMap::iterator i = consumers.find(tag);
+ if (i != consumers.end()) {
+ cancel(*get_pointer(i));
+ 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(mem_fun_ref(&DeliveryRecord::cancel), _1, tag));
+
+ }
+}
+
+
+void SemanticState::startTx()
+{
+ txBuffer = TxBuffer::shared_ptr(new TxBuffer());
+}
+
+void SemanticState::commit(MessageStore* const store, bool completeOnCommit)
+{
+ if (!txBuffer) throw
+ CommandInvalidException(QPID_MSG("Session has not been selected for use with transactions"));
+
+ TxOp::shared_ptr txAck(completeOnCommit ?
+ static_cast<TxOp*>(new TxAck(accumulatedAck, unacked)) :
+ static_cast<TxOp*>(new TxAccept(accumulatedAck, unacked)));
+ txBuffer->enlist(txAck);
+ if (txBuffer->commitLocal(store)) {
+ accumulatedAck.clear();
+ }
+}
+
+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 CommandInvalidException(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);
+ delivery.addTo(outstanding);
+}
+
+bool SemanticState::checkPrefetch(intrusive_ptr<Message>& msg)
+{
+ bool countOk = !prefetchCount || prefetchCount > unacked.size();
+ bool sizeOk = !prefetchSize || prefetchSize > msg->contentSize() + outstanding.size || unacked.empty();
+ return countOk && sizeOk;
+}
+
+SemanticState::ConsumerImpl::ConsumerImpl(SemanticState* _parent,
+ DeliveryToken::shared_ptr _token,
+ const string& _name,
+ Queue::shared_ptr _queue,
+ bool ack,
+ bool _nolocal,
+ bool _acquire
+ ) :
+ Consumer(_acquire),
+ parent(_parent),
+ token(_token),
+ name(_name),
+ queue(_queue),
+ ackExpected(ack),
+ nolocal(_nolocal),
+ acquire(_acquire),
+ blocked(true),
+ windowing(true),
+ msgCredit(0),
+ byteCredit(0) {}
+
+bool SemanticState::ConsumerImpl::deliver(QueuedMessage& msg)
+{
+ allocateCredit(msg.payload);
+ DeliveryId deliveryTag =
+ parent->deliveryAdapter.deliver(msg, token);
+ if (windowing || ackExpected) {
+ parent->record(DeliveryRecord(msg, queue, name, token, deliveryTag, acquire, !ackExpected));
+ }
+ if (acquire && !ackExpected) {
+ queue->dequeue(0, msg.payload);
+ }
+ return true;
+}
+
+bool SemanticState::ConsumerImpl::filter(intrusive_ptr<Message> msg)
+{
+ return !(nolocal &&
+ &parent->getSession().getConnection() == msg->getPublisher());
+}
+
+bool SemanticState::ConsumerImpl::accept(intrusive_ptr<Message> msg)
+{
+ //TODO: remove the now redundant checks (channel.flow & basic|message.qos removed):
+ blocked = !(filter(msg) && checkCredit(msg) && parent->flowActive && (!ackExpected || parent->checkPrefetch(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& c)
+{
+ outputTasks.removeOutputTask(&c);
+ 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);
+ }
+}
+
+void SemanticState::route(intrusive_ptr<Message> msg, Deliverable& strategy) {
+ std::string exchangeName = msg->getExchangeName();
+ if (msg->isA<MessageTransferBody>()) {
+ msg->getProperties<DeliveryProperties>()->setExchange(exchangeName);
+ } else if (msg->isA<Message010TransferBody>()) {
+ msg->getProperties<DeliveryProperties010>()->setExchange(exchangeName);
+ }
+ if (!cacheExchange || cacheExchange->getName() != exchangeName){
+ cacheExchange = session.getBroker().getExchanges().get(exchangeName);
+ }
+
+ cacheExchange->route(strategy, msg->getRoutingKey(), msg->getApplicationHeaders());
+
+ if (!strategy.delivered) {
+ //TODO:if reject-unroutable, then reject
+ //else route to alternate exchange
+ if (cacheExchange->getAlternate()) {
+ cacheExchange->getAlternate()->route(strategy, msg->getRoutingKey(), msg->getApplicationHeaders());
+ }
+ }
+
+}
+
+void SemanticState::ackCumulative(DeliveryId id)
+{
+ ack(id, id, true);
+}
+
+void SemanticState::ackRange(DeliveryId first, DeliveryId last)
+{
+ ack(first, last, false);
+}
+
+void SemanticState::ack(DeliveryId first, DeliveryId last, bool cumulative)
+{
+ {
+ ack_iterator start = cumulative ? unacked.begin() :
+ find_if(unacked.begin(), unacked.end(), bind2nd(mem_fun_ref(&DeliveryRecord::matchOrAfter), first));
+ ack_iterator end = start;
+
+ if (cumulative || first != last) {
+ //need to find end (position it just after the last record in range)
+ end = find_if(start, unacked.end(), bind2nd(mem_fun_ref(&DeliveryRecord::after), last));
+ } else if (start != unacked.end()) {
+ //just acked single element (move end past it)
+ ++end;
+ }
+
+ for_each(start, end, boost::bind(&SemanticState::complete, this, _1));
+
+ if (txBuffer.get()) {
+ //in transactional mode, don't dequeue or remove, just
+ //maintain set of acknowledged messages:
+ accumulatedAck.update(cumulative ? accumulatedAck.mark : 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));
+ //then remove that slice from the unacked record:
+ unacked.remove_if(bind2nd(mem_fun_ref(&DeliveryRecord::coveredBy), &accumulatedAck));
+ accumulatedAck.clear();
+ dtxBuffer->enlist(txAck);
+ }
+ } else {
+ for_each(start, end, bind2nd(mem_fun_ref(&DeliveryRecord::dequeue), 0));
+ unacked.erase(start, end);
+ }
+ }//end of lock scope for delivery lock (TODO this is ugly, make it prettier)
+
+ //if the prefetch limit had previously been reached, or credit
+ //had expired in windowing mode there may be messages that can
+ //be now be delivered
+ requestDispatch();
+}
+
+void SemanticState::requestDispatch()
+{
+ for (ConsumerImplMap::iterator i = consumers.begin(); i != consumers.end(); i++) {
+ requestDispatch(*get_pointer(i));
+ }
+}
+
+void SemanticState::requestDispatch(ConsumerImpl& c)
+{
+ if(c.isBlocked()) {
+ c.doOutput();
+ }
+}
+
+void SemanticState::complete(DeliveryRecord& delivery)
+{
+ delivery.subtractFrom(outstanding);
+ ConsumerImplMap::iterator i = consumers.find(delivery.getTag());
+ if (i != consumers.end()) {
+ get_pointer(i)->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){
+ outstanding.reset();
+ //take copy and clear unacked as requeue may result in redelivery to this session
+ //which will in turn result in additions to unacked
+ std::list<DeliveryRecord> copy = unacked;
+ unacked.clear();
+ for_each(copy.rbegin(), copy.rend(), mem_fun_ref(&DeliveryRecord::requeue));
+ }else{
+ for_each(unacked.begin(), unacked.end(), bind2nd(mem_fun_ref(&DeliveryRecord::redeliver), 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();
+ }
+}
+
+bool SemanticState::get(DeliveryToken::shared_ptr token, Queue::shared_ptr queue, bool ackExpected)
+{
+ QueuedMessage msg = queue->dequeue();
+ if(msg.payload){
+ DeliveryId myDeliveryTag = deliveryAdapter.deliver(msg, token);
+ if(ackExpected){
+ unacked.push_back(DeliveryRecord(msg, queue, myDeliveryTag));
+ }
+ return true;
+ }else{
+ return false;
+ }
+}
+
+DeliveryId SemanticState::redeliver(QueuedMessage& msg, DeliveryToken::shared_ptr token)
+{
+ return deliveryAdapter.deliver(msg, token);
+}
+
+void SemanticState::flow(bool active)
+{
+ bool requestDelivery(!flowActive && active);
+ flowActive = active;
+ if (requestDelivery) {
+ //there may be messages that can be now be delivered
+ requestDispatch();
+ }
+}
+
+
+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 *get_pointer(i);
+ }
+}
+
+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(*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)
+{
+ ack_iterator start = find_if(unacked.begin(), unacked.end(), bind2nd(mem_fun_ref(&DeliveryRecord::matchOrAfter), first));
+ ack_iterator end = start;
+
+ if (start != unacked.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, unacked.end(), bind2nd(mem_fun_ref(&DeliveryRecord::after), last));
+ }
+ }
+ return AckRange(start, end);
+}
+
+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, bind2nd(mem_fun_ref(&DeliveryRecord::release), 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::doOutput()
+{
+ //TODO: think through properly
+ return queue->dispatch(*this);
+}
+
+void SemanticState::ConsumerImpl::notify()
+{
+ //TODO: think through properly
+ 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.update(first, last);//TODO convert accumulatedAck to SequenceSet
+
+ 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, bind2nd(mem_fun_ref(&DeliveryRecord::accept), 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();
+}
+
+}} // namespace qpid::broker
diff --git a/qpid/cpp/src/qpid/broker/SemanticState.h b/qpid/cpp/src/qpid/broker/SemanticState.h
new file mode 100644
index 0000000000..20a0239db0
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/SemanticState.h
@@ -0,0 +1,200 @@
+#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 "DeliveryToken.h"
+#include "DtxBuffer.h"
+#include "DtxManager.h"
+#include "NameGenerator.h"
+#include "Prefetch.h"
+#include "TxBuffer.h"
+
+#include "qpid/framing/FrameHandler.h"
+#include "qpid/framing/AccumulatedAck.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/sys/AggregateOutput.h"
+#include "qpid/shared_ptr.h"
+
+#include <list>
+#include <map>
+#include <vector>
+
+#include <boost/intrusive_ptr.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 framing::FrameHandler::Chains,
+ public sys::OutputTask,
+ private boost::noncopyable
+{
+ class ConsumerImpl : public Consumer, public sys::OutputTask
+ {
+ SemanticState* const parent;
+ const DeliveryToken::shared_ptr token;
+ const string name;
+ const Queue::shared_ptr queue;
+ const bool ackExpected;
+ const bool nolocal;
+ const bool acquire;
+ bool blocked;
+ bool windowing;
+ uint32_t msgCredit;
+ uint32_t byteCredit;
+
+ bool checkCredit(boost::intrusive_ptr<Message>& msg);
+ void allocateCredit(boost::intrusive_ptr<Message>& msg);
+
+ public:
+ ConsumerImpl(SemanticState* parent, DeliveryToken::shared_ptr token,
+ const string& name, Queue::shared_ptr queue,
+ bool ack, bool nolocal, bool acquire);
+ ~ConsumerImpl();
+ bool deliver(QueuedMessage& msg);
+ bool filter(boost::intrusive_ptr<Message> msg);
+ bool accept(boost::intrusive_ptr<Message> msg);
+ void notify();
+
+ 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() { return queue; }
+ bool isBlocked() const { return blocked; }
+
+ bool doOutput();
+ };
+
+ typedef boost::ptr_map<std::string,ConsumerImpl> ConsumerImplMap;
+ typedef std::map<std::string, DtxBuffer::shared_ptr> DtxBufferMap;
+
+ SessionContext& session;
+ DeliveryAdapter& deliveryAdapter;
+ Queue::shared_ptr defaultQueue;
+ ConsumerImplMap consumers;
+ uint32_t prefetchSize;
+ uint16_t prefetchCount;
+ Prefetch outstanding;
+ NameGenerator tagGenerator;
+ std::list<DeliveryRecord> unacked;
+ TxBuffer::shared_ptr txBuffer;
+ DtxBuffer::shared_ptr dtxBuffer;
+ bool dtxSelected;
+ DtxBufferMap suspendedXids;
+ framing::AccumulatedAck accumulatedAck;
+ bool flowActive;
+ boost::shared_ptr<Exchange> cacheExchange;
+ sys::AggregateOutput outputTasks;
+
+ void route(boost::intrusive_ptr<Message> msg, Deliverable& strategy);
+ void record(const DeliveryRecord& delivery);
+ bool checkPrefetch(boost::intrusive_ptr<Message>& msg);
+ void checkDtxTimeout();
+ ConsumerImpl& find(const std::string& destination);
+ void ack(DeliveryId deliveryTag, DeliveryId endTag, bool cumulative);
+ void complete(DeliveryRecord&);
+ AckRange findRange(DeliveryId first, DeliveryId last);
+ void requestDispatch();
+ void requestDispatch(ConsumerImpl&);
+ void cancel(ConsumerImpl&);
+
+ public:
+ SemanticState(DeliveryAdapter&, SessionContext&);
+ ~SemanticState();
+
+ SessionContext& getSession() { return session; }
+
+ /**
+ * 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;
+
+ uint32_t setPrefetchSize(uint32_t size){ return prefetchSize = size; }
+ uint16_t setPrefetchCount(uint16_t n){ return prefetchCount = n; }
+
+ bool exists(const string& consumerTag);
+
+ /**
+ *@param tagInOut - if empty it is updated with the generated token.
+ */
+ void consume(DeliveryToken::shared_ptr token, string& tagInOut, Queue::shared_ptr queue,
+ bool nolocal, bool ackRequired, bool acquire, bool exclusive, const framing::FieldTable* = 0);
+
+ 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);
+
+ bool get(DeliveryToken::shared_ptr token, Queue::shared_ptr queue, bool ackExpected);
+ void startTx();
+ void commit(MessageStore* const store, bool completeOnCommit);
+ 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 flow(bool active);
+ DeliveryId redeliver(QueuedMessage& msg, DeliveryToken::shared_ptr token);
+ 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 doOutput() { return outputTasks.doOutput(); }
+
+ //preview only (completed == ack):
+ void ackCumulative(DeliveryId deliveryTag);
+ void ackRange(DeliveryId deliveryTag, DeliveryId endTag);
+
+ //final 0-10 spec (completed and accepted are distinct):
+ void completed(DeliveryId deliveryTag, DeliveryId endTag);
+ void accepted(DeliveryId deliveryTag, DeliveryId endTag);
+};
+
+}} // namespace qpid::broker
+
+
+
+
+#endif /*!QPID_BROKER_SEMANTICSTATE_H*/
diff --git a/qpid/cpp/src/qpid/broker/SessionAdapter.cpp b/qpid/cpp/src/qpid/broker/SessionAdapter.cpp
new file mode 100644
index 0000000000..8093c7c174
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/SessionAdapter.cpp
@@ -0,0 +1,590 @@
+/*
+ *
+ * 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 "DeliveryToken.h"
+#include "MessageDelivery.h"
+#include "Queue.h"
+#include "qpid/Exception.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/framing/constants.h"
+#include "qpid/log/Statement.h"
+#include "qpid/amqp_0_10/exceptions.h"
+#include <boost/format.hpp>
+#include <boost/cast.hpp>
+#include <boost/bind.hpp>
+
+namespace qpid {
+namespace broker {
+
+using namespace qpid;
+using namespace qpid::framing;
+
+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){
+
+ //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);
+ }
+ }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*/){
+ //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);
+}
+
+Exchange010QueryResult SessionAdapter::ExchangeHandlerImpl::query(const string& name)
+{
+ try {
+ Exchange::shared_ptr exchange(getBroker().getExchanges().get(name));
+ return Exchange010QueryResult(exchange->getType(), exchange->isDurable(), false, exchange->getArgs());
+ } catch (const ChannelException& e) {
+ return Exchange010QueryResult("", false, true, FieldTable());
+ }
+}
+void SessionAdapter::ExchangeHandlerImpl::bind(const string& queueName,
+ const string& exchangeName, const string& routingKey,
+ const FieldTable& arguments){
+
+ 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);
+ }
+ }
+ }else{
+ throw NotFoundException(
+ "Bind failed. No such exchange: " + exchangeName);
+ }
+}
+
+void
+SessionAdapter::ExchangeHandlerImpl::unbind(const string& queueName,
+ const string& exchangeName,
+ const string& routingKey)
+{
+ 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) && exchange->isDurable() && queue->isDurable()) {
+ getBroker().getStore().unbind(*exchange, *queue, routingKey, FieldTable());
+ }
+
+}
+
+Exchange010BoundResult SessionAdapter::ExchangeHandlerImpl::bound(const std::string& exchangeName,
+ const std::string& queueName,
+ const std::string& key,
+ const framing::FieldTable& args)
+{
+ Exchange::shared_ptr exchange;
+ try {
+ exchange = getBroker().getExchanges().get(exchangeName);
+ } catch (const ChannelException&) {}
+
+ Queue::shared_ptr queue;
+ if (!queueName.empty()) {
+ queue = getBroker().getQueues().find(queueName);
+ }
+
+ if (!exchange) {
+ return Exchange010BoundResult(true, false, false, false, false);
+ } else if (!queueName.empty() && !queue) {
+ return Exchange010BoundResult(false, true, false, false, false);
+ } else if (exchange->isBound(queue, key.empty() ? 0 : &key, args.count() > 0 ? &args : &args)) {
+ return Exchange010BoundResult(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 Exchange010BoundResult(false, false, !queueMatched, !keyMatched, !argsMatched);
+ }
+}
+
+SessionAdapter::QueueHandlerImpl::QueueHandlerImpl(SemanticState& session) : HandlerHelper(session), broker(getBroker())
+{}
+
+
+SessionAdapter::QueueHandlerImpl::~QueueHandlerImpl()
+{
+ 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);
+}
+
+
+Queue010QueryResult SessionAdapter::QueueHandlerImpl::query(const string& name)
+{
+ Queue::shared_ptr queue = getQueue(name);
+ Exchange::shared_ptr alternateExchange = queue->getAlternateExchange();
+
+ return Queue010QueryResult(queue->getName(),
+ alternateExchange ? alternateExchange->getName() : "",
+ queue->isDurable(),
+ queue->hasExclusiveOwner(),
+ queue->isAutoDelete(),
+ queue->getSettings(),
+ queue->getMessageCount(),
+ queue->getConsumerCount());
+}
+
+void SessionAdapter::QueueHandlerImpl::declare(const string& name, const string& alternateExchange,
+ bool passive, bool durable, bool exclusive,
+ bool autoDelete, const qpid::framing::FieldTable& arguments){
+
+ 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 ? this : 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(this)) {
+ exclusiveQueues.push_back(queue);
+ }
+ }
+ }
+ if (exclusive && !queue->isExclusiveOwner(this))
+ throw ResourceLockedException(
+ QPID_MSG("Cannot grant exclusive access to queue "
+ << queue->getName()));
+}
+
+
+void SessionAdapter::QueueHandlerImpl::purge(const string& queue){
+ getQueue(queue)->purge();
+}
+
+void SessionAdapter::QueueHandlerImpl::delete_(const string& queue, bool ifUnused, bool ifEmpty){
+ ChannelException error(0, "");
+ Queue::shared_ptr q = getQueue(queue);
+ 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 = 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);
+ }
+}
+
+
+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
+}
+
+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*/,//TODO implement resume behaviour
+ uint64_t /*resumeTtl*/,
+ const FieldTable& arguments)
+{
+ Queue::shared_ptr queue = getQueue(queueName);
+ if(!destination.empty() && state.exists(destination))
+ throw NotAllowedException(QPID_MSG("Consumer tags must be unique"));
+
+ string tag = destination;
+ state.consume(MessageDelivery::getMessageDeliveryToken(destination, acceptMode, acquireMode),
+ tag, queue, false, //TODO get rid of no-local
+ acceptMode == 0, acquireMode == 0, exclusive, &arguments);
+}
+
+void
+SessionAdapter::MessageHandlerImpl::cancel(const string& destination )
+{
+ state.cancel(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, u_int8_t unit, u_int32_t value)
+{
+ if (unit == 0) {
+ //message
+ state.addMessageCredit(destination, value);
+ } else if (unit == 1) {
+ //bytes
+ state.addByteCredit(destination, value);
+ } else {
+ //unknown
+ throw SyntaxErrorException(QPID_MSG("Invalid value for unit " << unit));
+ }
+
+}
+
+void SessionAdapter::MessageHandlerImpl::setFlowMode(const std::string& destination, u_int8_t mode)
+{
+ if (mode == 0) {
+ //credit
+ state.setCreditMode(destination);
+ } else if (mode == 1) {
+ //window
+ state.setWindowMode(destination);
+ } else{
+ throw SyntaxErrorException(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::Message010AcquireResult SessionAdapter::MessageHandlerImpl::acquire(const framing::SequenceSet& transfers)
+{
+ //TODO: change this when SequenceNumberSet is deleted along with preview code
+ 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 Message010AcquireResult(acquisitions);
+}
+
+
+void SessionAdapter::ExecutionHandlerImpl::sync()
+{
+ //TODO
+}
+
+void SessionAdapter::ExecutionHandlerImpl::result(uint32_t /*commandId*/, const string& /*value*/)
+{
+ //TODO
+}
+
+void SessionAdapter::ExecutionHandlerImpl::exception(uint16_t /*errorCode*/,
+ uint32_t /*commandId*/,
+ uint8_t /*classCode*/,
+ uint8_t /*commandCode*/,
+ uint8_t /*fieldIndex*/,
+ const std::string& /*description*/,
+ const framing::FieldTable& /*errorInfo*/)
+{
+ //TODO
+}
+
+
+
+void SessionAdapter::TxHandlerImpl::select()
+{
+ state.startTx();
+}
+
+void SessionAdapter::TxHandlerImpl::commit()
+{
+ state.commit(&getBroker().getStore(), false);
+}
+
+void SessionAdapter::TxHandlerImpl::rollback()
+{
+ state.rollback();
+}
+
+std::string SessionAdapter::DtxHandlerImpl::convert(const framing::Xid010& xid)
+{
+ std::stringstream out;
+ out << xid.getFormat() << xid.getGlobalId() << xid.getBranchId();
+ return out.str();
+}
+
+
+void SessionAdapter::DtxHandlerImpl::select()
+{
+ state.selectDtx();
+}
+
+Dtx010EndResult SessionAdapter::DtxHandlerImpl::end(const Xid010& 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 Dtx010EndResult(XA_RBROLLBACK);
+ }
+ } else {
+ if (suspend) {
+ state.suspendDtx(convert(xid));
+ } else {
+ state.endDtx(convert(xid), false);
+ }
+ return Dtx010EndResult(XA_OK);
+ }
+ } catch (const DtxTimeoutException& e) {
+ return Dtx010EndResult(XA_RBTIMEOUT);
+ }
+}
+
+Dtx010StartResult SessionAdapter::DtxHandlerImpl::start(const Xid010& 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 Dtx010StartResult(XA_OK);
+ } catch (const DtxTimeoutException& e) {
+ return Dtx010StartResult(XA_RBTIMEOUT);
+ }
+}
+
+Dtx010PrepareResult SessionAdapter::DtxHandlerImpl::prepare(const Xid010& xid)
+{
+ try {
+ bool ok = getBroker().getDtxManager().prepare(convert(xid));
+ return Dtx010PrepareResult(ok ? XA_OK : XA_RBROLLBACK);
+ } catch (const DtxTimeoutException& e) {
+ return Dtx010PrepareResult(XA_RBTIMEOUT);
+ }
+}
+
+Dtx010CommitResult SessionAdapter::DtxHandlerImpl::commit(const Xid010& xid,
+ bool onePhase)
+{
+ try {
+ bool ok = getBroker().getDtxManager().commit(convert(xid), onePhase);
+ return Dtx010CommitResult(ok ? XA_OK : XA_RBROLLBACK);
+ } catch (const DtxTimeoutException& e) {
+ return Dtx010CommitResult(XA_RBTIMEOUT);
+ }
+}
+
+
+Dtx010RollbackResult SessionAdapter::DtxHandlerImpl::rollback(const Xid010& xid)
+{
+ try {
+ getBroker().getDtxManager().rollback(convert(xid));
+ return Dtx010RollbackResult(XA_OK);
+ } catch (const DtxTimeoutException& e) {
+ return Dtx010RollbackResult(XA_RBTIMEOUT);
+ }
+}
+
+Dtx010RecoverResult SessionAdapter::DtxHandlerImpl::recover()
+{
+ std::set<std::string> xids;
+ getBroker().getStore().collectPreparedXids(xids);
+
+ //TODO: remove the need to copy from one container type to another
+ std::vector<std::string> data;
+ for (std::set<std::string>::iterator i = xids.begin(); i != xids.end(); i++) {
+ data.push_back(*i);
+ }
+ Array indoubt(data);
+ return Dtx010RecoverResult(indoubt);
+}
+
+void SessionAdapter::DtxHandlerImpl::forget(const Xid010& xid)
+{
+ //Currently no heuristic completion is supported, so this should never be used.
+ throw CommandInvalidException(QPID_MSG("Forget is invalid. Branch with xid " << xid << " not heuristically completed!"));
+}
+
+Dtx010GetTimeoutResult SessionAdapter::DtxHandlerImpl::getTimeout(const Xid010& xid)
+{
+ uint32_t timeout = getBroker().getDtxManager().getTimeout(convert(xid));
+ return Dtx010GetTimeoutResult(timeout);
+}
+
+
+void SessionAdapter::DtxHandlerImpl::setTimeout(const Xid010& xid,
+ u_int32_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 amqp_0_10::IllegalArgumentException(QPID_MSG("No queue name specified."));
+ } else {
+ queue = session.getBroker().getQueues().find(name);
+ if (!queue)
+ throw amqp_0_10::NotFoundException(QPID_MSG("Queue not found: "<<name));
+ }
+ return queue;
+}
+
+}} // namespace qpid::broker
+
+
diff --git a/qpid/cpp/src/qpid/broker/SessionAdapter.h b/qpid/cpp/src/qpid/broker/SessionAdapter.h
new file mode 100644
index 0000000000..a77f1b5d77
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/SessionAdapter.h
@@ -0,0 +1,269 @@
+#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/SequenceSet.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();}
+
+ Message010Handler* getMessage010Handler(){ return &messageImpl; }
+ Exchange010Handler* getExchange010Handler(){ return &exchangeImpl; }
+ Queue010Handler* getQueue010Handler(){ return &queueImpl; }
+ Execution010Handler* getExecution010Handler(){ return &executionImpl; }
+ Tx010Handler* getTx010Handler(){ return &txImpl; }
+ Dtx010Handler* getDtx010Handler(){ return &dtxImpl; }
+
+ BasicHandler* getBasicHandler() { throw framing::NotImplementedException("Class not implemented"); }
+ ExchangeHandler* getExchangeHandler(){ throw framing::NotImplementedException("Class not implemented"); }
+ BindingHandler* getBindingHandler(){ throw framing::NotImplementedException("Class not implemented"); }
+ QueueHandler* getQueueHandler(){ throw framing::NotImplementedException("Class not implemented"); }
+ TxHandler* getTxHandler(){ throw framing::NotImplementedException("Class not implemented"); }
+ MessageHandler* getMessageHandler(){ throw framing::NotImplementedException("Class not implemented"); }
+ DtxCoordinationHandler* getDtxCoordinationHandler(){ throw framing::NotImplementedException("Class not implemented"); }
+ DtxDemarcationHandler* getDtxDemarcationHandler(){ throw framing::NotImplementedException("Class not implemented"); }
+ AccessHandler* getAccessHandler() { throw framing::NotImplementedException("Class not implemented"); }
+ FileHandler* getFileHandler() { throw framing::NotImplementedException("Class not implemented"); }
+ StreamHandler* getStreamHandler() { throw framing::NotImplementedException("Class not implemented"); }
+ TunnelHandler* getTunnelHandler() { throw framing::NotImplementedException("Class not implemented"); }
+ ExecutionHandler* getExecutionHandler() { throw framing::NotImplementedException("Class not implemented"); }
+ ConnectionHandler* getConnectionHandler() { throw framing::NotImplementedException("Class not implemented"); }
+ SessionHandler* getSessionHandler() { throw framing::NotImplementedException("Class not implemented"); }
+ Connection010Handler* getConnection010Handler() { throw framing::NotImplementedException("Class not implemented"); }
+ Session010Handler* getSession010Handler() { 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 Exchange010Handler,
+ 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::Exchange010QueryResult 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::Exchange010BoundResult 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 Queue010Handler,
+ public HandlerHelper, public OwnershipToken
+ {
+ 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::Queue010QueryResult query(const std::string& queue);
+ bool isLocal(const ConnectionToken* t) const;
+ };
+
+ class MessageHandlerImpl :
+ public Message010Handler,
+ 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::Message010AcquireResult 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);
+
+ };
+
+ class ExecutionHandlerImpl : public Execution010Handler, public HandlerHelper
+ {
+ public:
+ ExecutionHandlerImpl(SemanticState& session) : HandlerHelper(session) {}
+
+ void sync();
+ void result(uint32_t commandId, const string& value);
+ void exception(uint16_t errorCode,
+ uint32_t commandId,
+ uint8_t classCode,
+ uint8_t commandCode,
+ uint8_t fieldIndex,
+ const std::string& description,
+ const framing::FieldTable& errorInfo);
+
+ };
+
+ class TxHandlerImpl : public Tx010Handler, public HandlerHelper
+ {
+ public:
+ TxHandlerImpl(SemanticState& session) : HandlerHelper(session) {}
+
+ void select();
+ void commit();
+ void rollback();
+ };
+
+ class DtxHandlerImpl : public Dtx010Handler, public HandlerHelper
+ {
+ std::string convert(const framing::Xid010& xid);
+
+ public:
+ DtxHandlerImpl(SemanticState& session) : HandlerHelper(session) {}
+
+ void select();
+
+ framing::Dtx010StartResult start(const framing::Xid010& xid,
+ bool join,
+ bool resume);
+
+ framing::Dtx010EndResult end(const framing::Xid010& xid,
+ bool fail,
+ bool suspend);
+
+ framing::Dtx010CommitResult commit(const framing::Xid010& xid,
+ bool onePhase);
+
+ void forget(const framing::Xid010& xid);
+
+ framing::Dtx010GetTimeoutResult getTimeout(const framing::Xid010& xid);
+
+ framing::Dtx010PrepareResult prepare(const framing::Xid010& xid);
+
+ framing::Dtx010RecoverResult recover();
+
+ framing::Dtx010RollbackResult rollback(const framing::Xid010& xid);
+
+ void setTimeout(const framing::Xid010& 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/qpid/cpp/src/qpid/broker/SessionContext.h b/qpid/cpp/src/qpid/broker/SessionContext.h
new file mode 100644
index 0000000000..e3cc0a5fa3
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/SessionContext.h
@@ -0,0 +1,51 @@
+#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 <boost/noncopyable.hpp>
+
+namespace qpid {
+namespace broker {
+
+class SessionContext : 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/qpid/cpp/src/qpid/broker/SessionHandler.cpp b/qpid/cpp/src/qpid/broker/SessionHandler.cpp
new file mode 100644
index 0000000000..3baa3a89a7
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/SessionHandler.cpp
@@ -0,0 +1,228 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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 "ConnectionState.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/framing/constants.h"
+#include "qpid/framing/ClientInvoker.h"
+#include "qpid/framing/ServerInvoker.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)
+ : InOutHandler(0, &out),
+ connection(c), channel(ch, &c.getOutput()),
+ proxy(out), // Via my own handleOut() for L2 data.
+ peerSession(channel), // Direct to channel for L2 commands.
+ ignoring(false) {}
+
+SessionHandler::~SessionHandler() {}
+
+namespace {
+ClassId classId(AMQMethodBody* m) { return m ? m->amqpMethodId() : 0; }
+MethodId methodId(AMQMethodBody* m) { return m ? m->amqpClassId() : 0; }
+} // namespace
+
+void SessionHandler::handleIn(AMQFrame& f) {
+ // Note on channel states: a channel is open if session != 0. A
+ // channel that is closed (session == 0) can be in the "ignoring"
+ // state. This is a temporary state after we have sent a channel
+ // exception, where extra frames might arrive that should be
+ // ignored.
+ //
+ AMQMethodBody* m = f.getBody()->getMethod();
+ try {
+ if (!ignoring) {
+ if (m && invoke(static_cast<AMQP_ServerOperations::Session010Handler&>(*this), *m)) {
+ return;
+ } else if (session.get()) {
+ session->handle(f);
+ } else {
+ throw ChannelErrorException(
+ QPID_MSG("Channel " << channel.get() << " is not open"));
+ }
+ }
+ }catch(const ConnectionException& e){
+ connection.close(e.code, e.what(), classId(m), methodId(m));
+ }catch(const std::exception& e){
+ connection.close(
+ framing::INTERNAL_ERROR, e.what(), classId(m), methodId(m));
+ }
+}
+
+void SessionHandler::destroy() {
+ ignoring=true; // Ignore trailing frames sent by client.
+ session->detach();
+ session.reset();
+}
+
+void SessionHandler::handleOut(AMQFrame& f) {
+ channel.handle(f); // Send it.
+ if (session->sent(f))
+ peerSession.flush(false, false, true);
+}
+
+void SessionHandler::assertAttached(const char* method) const {
+ if (!session.get()) {
+ std::cout << "SessionHandler::assertAttached() failed for " << method << std::endl;
+ throw ChannelErrorException(
+ QPID_MSG(method << " failed: No session for channel "
+ << getChannel()));
+ }
+}
+
+void SessionHandler::assertClosed(const char* method) const {
+ if (session.get())
+ throw ChannelBusyException(
+ QPID_MSG(method << " failed: channel " << channel.get()
+ << " is already open."));
+}
+
+void SessionHandler::localSuspend() {
+ if (session.get() && session->isAttached()) {
+ session->detach();
+ connection.broker.getSessionManager().suspend(session);
+ session.reset();
+ }
+}
+
+
+ConnectionState& SessionHandler::getConnection() { return connection; }
+const ConnectionState& SessionHandler::getConnection() const { return connection; }
+
+//new methods:
+void SessionHandler::attach(const std::string& name, bool /*force*/)
+{
+ //TODO: need to revise session manager to support resume as well
+ assertClosed("attach");
+ std::auto_ptr<SessionState> state(
+ connection.broker.getSessionManager().open(*this, 0));
+ session.reset(state.release());
+ peerSession.attached(name);
+ peerSession.commandPoint(session->nextOut, 0);
+}
+
+void SessionHandler::attached(const std::string& /*name*/)
+{
+ std::auto_ptr<SessionState> state(connection.broker.getSessionManager().open(*this, 0));
+ session.reset(state.release());
+}
+
+void SessionHandler::detach(const std::string& name)
+{
+ assertAttached("detach");
+ localSuspend();
+ peerSession.detached(name, 0);
+ assert(&connection.getChannel(channel.get()) == this);
+ connection.closeChannel(channel.get());
+}
+
+void SessionHandler::detached(const std::string& name, uint8_t code)
+{
+ ignoring=false;
+ session->detach();
+ session.reset();
+ if (code) {
+ //no error
+ } else {
+ //error occured
+ QPID_LOG(warning, "Received session.closed: "<< name << " " << code);
+ }
+}
+
+void SessionHandler::requestTimeout(uint32_t t)
+{
+ session->setTimeout(t);
+ //proxy.timeout(t);
+}
+
+void SessionHandler::timeout(uint32_t)
+{
+ //not sure what we need to do on the server for this...
+}
+
+void SessionHandler::commandPoint(const framing::SequenceNumber& id, uint64_t offset)
+{
+ if (offset) throw NotImplementedException("Non-zero byte offset not yet supported for command-point");
+
+ session->nextIn = id;
+}
+
+void SessionHandler::expected(const framing::SequenceSet& commands, const framing::Array& fragments)
+{
+ if (!commands.empty() || fragments.size()) {
+ throw NotImplementedException("Session resumption not yet supported");
+ }
+}
+
+void SessionHandler::confirmed(const framing::SequenceSet& /*commands*/, const framing::Array& /*fragments*/)
+{
+ //don't really care too much about this yet
+}
+
+void SessionHandler::completed(const framing::SequenceSet& commands, bool timelyReply)
+{
+ session->complete(commands);
+ if (timelyReply) {
+ peerSession.knownCompleted(session->knownCompleted);
+ session->knownCompleted.clear();
+ }
+}
+
+void SessionHandler::knownCompleted(const framing::SequenceSet& commands)
+{
+ session->completed.remove(commands);
+}
+
+void SessionHandler::flush(bool expected, bool confirmed, bool completed)
+{
+ if (expected) {
+ peerSession.expected(SequenceSet(session->nextIn), Array());
+ }
+ if (confirmed) {
+ peerSession.confirmed(session->completed, Array());
+ }
+ if (completed) {
+ peerSession.completed(session->completed, true);
+ }
+}
+
+
+void SessionHandler::sendCompletion()
+{
+ peerSession.completed(session->completed, true);
+}
+
+void SessionHandler::gap(const framing::SequenceSet& /*commands*/)
+{
+ throw NotImplementedException("gap not yet supported");
+}
+
+}} // namespace qpid::broker
diff --git a/qpid/cpp/src/qpid/broker/SessionHandler.h b/qpid/cpp/src/qpid/broker/SessionHandler.h
new file mode 100644
index 0000000000..fa013a1c15
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/SessionHandler.h
@@ -0,0 +1,116 @@
+#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/framing/FrameHandler.h"
+#include "qpid/framing/AMQP_ClientOperations.h"
+#include "qpid/framing/AMQP_ServerOperations.h"
+#include "qpid/framing/AMQP_ClientProxy.h"
+#include "qpid/framing/amqp_types.h"
+#include "qpid/framing/Array.h"
+#include "qpid/framing/ChannelHandler.h"
+#include "qpid/framing/SequenceNumber.h"
+#include "qpid/framing/SequenceSet.h"
+
+#include <boost/noncopyable.hpp>
+
+namespace qpid {
+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 framing::AMQP_ServerOperations::Session010Handler,
+ public framing::FrameHandler::InOutHandler,
+ private boost::noncopyable
+{
+ public:
+ SessionHandler(Connection&, framing::ChannelId);
+ ~SessionHandler();
+
+ /** Returns 0 if not attached to a session */
+ SessionState* getSession() { return session.get(); }
+ const SessionState* getSession() const { return session.get(); }
+
+ framing::ChannelId getChannel() const { return channel.get(); }
+
+ ConnectionState& getConnection();
+ const ConnectionState& getConnection() const;
+
+ framing::AMQP_ClientProxy& getProxy() { return proxy; }
+ const framing::AMQP_ClientProxy& getProxy() const { return proxy; }
+
+ // Called by closing connection.
+ void localSuspend();
+ void detach() { localSuspend(); }
+ void sendCompletion();
+ void destroy();
+
+ protected:
+ void handleIn(framing::AMQFrame&);
+ void handleOut(framing::AMQFrame&);
+
+ private:
+ //new 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);
+
+ //hacks for old generator:
+ void commandPoint(uint32_t id, uint64_t offset) { commandPoint(framing::SequenceNumber(id), offset); }
+
+ void assertAttached(const char* method) const;
+ void assertActive(const char* method) const;
+ void assertClosed(const char* method) const;
+
+ Connection& connection;
+ framing::ChannelHandler channel;
+ framing::AMQP_ClientProxy proxy;
+ framing::AMQP_ClientProxy::Session010 peerSession;
+ bool ignoring;
+ std::auto_ptr<SessionState> session;
+};
+
+}} // namespace qpid::broker
+
+
+
+#endif /*!QPID_BROKER_SESSIONHANDLER_H*/
diff --git a/qpid/cpp/src/qpid/broker/SessionManager.cpp b/qpid/cpp/src/qpid/broker/SessionManager.cpp
new file mode 100644
index 0000000000..6e235e32c3
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/SessionManager.cpp
@@ -0,0 +1,113 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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(uint32_t a) : ack(a) {}
+
+SessionManager::~SessionManager() {}
+
+// FIXME aconway 2008-02-01: pass handler*, allow open unattached.
+std::auto_ptr<SessionState> SessionManager::open(
+ SessionHandler& h, uint32_t timeout_)
+{
+ Mutex::ScopedLock l(lock);
+ std::auto_ptr<SessionState> session(
+ new SessionState(this, &h, timeout_, ack));
+ active.insert(session->getId());
+ for_each(observers.begin(), observers.end(),
+ boost::bind(&Observer::opened, _1,boost::ref(*session)));
+ return session;
+}
+
+void SessionManager::suspend(std::auto_ptr<SessionState> session) {
+ Mutex::ScopedLock l(lock);
+ active.erase(session->getId());
+ session->suspend();
+ session->expiry = AbsTime(now(),session->getTimeout()*TIME_SEC);
+ if (session->mgmtObject.get() != 0)
+ session->mgmtObject->set_expireTime ((uint64_t) Duration (session->expiry));
+ suspended.push_back(session.release()); // In expiry order
+ eraseExpired();
+}
+
+std::auto_ptr<SessionState> SessionManager::resume(const Uuid& id)
+{
+ Mutex::ScopedLock l(lock);
+ eraseExpired();
+ if (active.find(id) != active.end())
+ throw SessionBusyException(
+ QPID_MSG("Session already active: " << id));
+ Suspended::iterator i = std::find_if(
+ suspended.begin(), suspended.end(),
+ boost::bind(std::equal_to<Uuid>(), id, boost::bind(&SessionState::getId, _1))
+ );
+ if (i == suspended.end())
+ throw InvalidArgumentException(
+ QPID_MSG("No suspended session with id=" << id));
+ active.insert(id);
+ std::auto_ptr<SessionState> state(suspended.release(i).release());
+ return state;
+}
+
+void SessionManager::erase(const framing::Uuid& id)
+{
+ Mutex::ScopedLock l(lock);
+ active.erase(id);
+}
+
+void SessionManager::eraseExpired() {
+ // Called with lock held.
+ if (!suspended.empty()) {
+ Suspended::iterator keep = std::lower_bound(
+ suspended.begin(), suspended.end(), now(),
+ boost::bind(std::less<AbsTime>(), boost::bind(&SessionState::expiry, _1), _2));
+ if (suspended.begin() != keep) {
+ QPID_LOG(debug, "Expiring sessions: " << log::formatList(suspended.begin(), keep));
+ suspended.erase(suspended.begin(), keep);
+ }
+ }
+}
+
+void SessionManager::add(const intrusive_ptr<Observer>& o) {
+ observers.push_back(o);
+}
+
+}} // namespace qpid::broker
diff --git a/qpid/cpp/src/qpid/broker/SessionManager.h b/qpid/cpp/src/qpid/broker/SessionManager.h
new file mode 100644
index 0000000000..cc2190c2d1
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/SessionManager.h
@@ -0,0 +1,101 @@
+#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/framing/Uuid.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 SessionState;
+class SessionHandler;
+
+/**
+ * Create and manage SessionState objects.
+ */
+class SessionManager : private boost::noncopyable {
+ public:
+ /**
+ * Observer notified of SessionManager events.
+ */
+ struct Observer : public RefCounted {
+ virtual void opened(SessionState&) {}
+ };
+
+ SessionManager(uint32_t ack);
+
+ ~SessionManager();
+
+ /** Open a new active session, caller takes ownership */
+ std::auto_ptr<SessionState> open(SessionHandler& c, uint32_t timeout_);
+
+ /** Suspend a session, start it's timeout counter.
+ * The factory takes ownership.
+ */
+ void suspend(std::auto_ptr<SessionState> session);
+
+ /** Resume a suspended session.
+ *@throw Exception if timed out or non-existant.
+ */
+ std::auto_ptr<SessionState> resume(const framing::Uuid&);
+
+ /** Add an Observer. */
+ void add(const boost::intrusive_ptr<Observer>&);
+
+ private:
+ typedef boost::ptr_vector<SessionState> Suspended;
+ typedef std::set<framing::Uuid> Active;
+ typedef std::vector<boost::intrusive_ptr<Observer> > Observers;
+
+ void erase(const framing::Uuid&);
+ void eraseExpired();
+
+ sys::Mutex lock;
+ Suspended suspended;
+ Active active;
+ uint32_t ack;
+ Observers observers;
+
+ friend class SessionState; // removes deleted sessions from active set.
+};
+
+
+
+}} // namespace qpid::broker
+
+
+
+
+
+#endif /*!QPID_BROKER_SESSIONMANAGER_H*/
diff --git a/qpid/cpp/src/qpid/broker/SessionState.cpp b/qpid/cpp/src/qpid/broker/SessionState.cpp
new file mode 100644
index 0000000000..d719bbe145
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/SessionState.cpp
@@ -0,0 +1,288 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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 "MessageDelivery.h"
+#include "SemanticHandler.h"
+#include "SessionManager.h"
+#include "SessionHandler.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/framing/ServerInvoker.h"
+
+#include <boost/bind.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;
+
+SessionState::SessionState(
+ SessionManager* f, SessionHandler* h, uint32_t timeout_, uint32_t ack)
+ : framing::SessionState(ack, timeout_ > 0), nextOut(0),
+ factory(f), handler(h), id(true), timeout(timeout_),
+ broker(h->getConnection().broker),
+ version(h->getConnection().getVersion()),
+ semanticState(*this, *this),
+ adapter(semanticState),
+ msgBuilder(&broker.getStore(), broker.getStagingThreshold()),
+ ackOp(boost::bind(&SemanticState::completed, &semanticState, _1, _2)),
+ enqueuedOp(boost::bind(&SessionState::enqueued, this, _1))
+{
+ getConnection().outputTasks.addOutputTask(&semanticState);
+
+ Manageable* parent = broker.GetVhostObject ();
+
+ if (parent != 0)
+ {
+ ManagementAgent::shared_ptr agent = ManagementAgent::getAgent ();
+
+ if (agent.get () != 0)
+ {
+ mgmtObject = management::Session::shared_ptr
+ (new management::Session (this, parent, id.str ()));
+ mgmtObject->set_attached (1);
+ mgmtObject->set_clientRef (h->getConnection().GetManagementObject()->getObjectId());
+ mgmtObject->set_channelId (h->getChannel());
+ mgmtObject->set_detachedLifespan (getTimeout());
+ agent->addObject (mgmtObject);
+ }
+ }
+}
+
+SessionState::~SessionState() {
+ // Remove ID from active session list.
+ if (factory)
+ factory->erase(getId());
+ if (mgmtObject.get () != 0)
+ mgmtObject->resourceDestroy ();
+}
+
+SessionHandler* SessionState::getHandler() {
+ return handler;
+}
+
+AMQP_ClientProxy& SessionState::getProxy() {
+ assert(isAttached());
+ return getHandler()->getProxy();
+}
+
+ConnectionState& SessionState::getConnection() {
+ assert(isAttached());
+ return getHandler()->getConnection();
+}
+
+bool SessionState::isLocal(const ConnectionToken* t) const
+{
+ return isAttached() && &(handler->getConnection()) == t;
+}
+
+void SessionState::detach() {
+ getConnection().outputTasks.removeOutputTask(&semanticState);
+ Mutex::ScopedLock l(lock);
+ handler = 0;
+ if (mgmtObject.get() != 0)
+ {
+ mgmtObject->set_attached (0);
+ }
+}
+
+void SessionState::attach(SessionHandler& h) {
+ {
+ Mutex::ScopedLock l(lock);
+ handler = &h;
+ if (mgmtObject.get() != 0)
+ {
+ mgmtObject->set_attached (1);
+ mgmtObject->set_clientRef (h.getConnection().GetManagementObject()->getObjectId());
+ mgmtObject->set_channelId (h.getChannel());
+ }
+ }
+ h.getConnection().outputTasks.addOutputTask(&semanticState);
+}
+
+void SessionState::activateOutput()
+{
+ Mutex::ScopedLock l(lock);
+ if (isAttached()) {
+ getConnection().outputTasks.activateOutput();
+ }
+}
+ //This class could be used as the callback for queue notifications
+ //if not attached, it can simply ignore the callback, else pass it
+ //on to the connection
+
+ManagementObject::shared_ptr SessionState::GetManagementObject (void) const
+{
+ return dynamic_pointer_cast<ManagementObject> (mgmtObject);
+}
+
+Manageable::status_t SessionState::ManagementMethod (uint32_t methodId,
+ Args& /*args*/)
+{
+ Manageable::status_t status = Manageable::STATUS_UNKNOWN_METHOD;
+
+ switch (methodId)
+ {
+ case management::Session::METHOD_DETACH :
+ if (handler != 0)
+ {
+ handler->detach();
+ }
+ status = Manageable::STATUS_OK;
+ break;
+
+ case management::Session::METHOD_CLOSE :
+ /*
+ if (handler != 0)
+ {
+ handler->getConnection().closeChannel(handler->getChannel());
+ }
+ status = Manageable::STATUS_OK;
+ break;
+ */
+
+ case management::Session::METHOD_SOLICITACK :
+ case management::Session::METHOD_RESETLIFESPAN :
+ status = Manageable::STATUS_NOT_IMPLEMENTED;
+ break;
+ }
+
+ return status;
+}
+
+void SessionState::handleCommand(framing::AMQMethodBody* method, SequenceNumber& id)
+{
+ id = nextIn++;
+ Invoker::Result invocation = invoke(adapter, *method);
+ completed.add(id);
+
+ if (!invocation.wasHandled()) {
+ throw NotImplementedException("Not implemented");
+ } else if (invocation.hasResult()) {
+ nextOut++;//execution result is now a command, so the counter must be incremented
+ getProxy().getExecution010().result(id, invocation.getResult());
+ }
+ if (method->isSync()) {
+ incomplete.process(enqueuedOp, true);
+ sendCompletion();
+ }
+ //TODO: if window gets too large send unsolicited completion
+}
+
+void SessionState::handleContent(AMQFrame& frame, SequenceNumber& id)
+{
+ intrusive_ptr<Message> msg(msgBuilder.getMessage());
+ if (frame.getBof() && frame.getBos()) {//start of frameset
+ id = nextIn++;
+ msgBuilder.start(id);
+ msg = msgBuilder.getMessage();
+ } else {
+ id = msg->getCommandId();
+ }
+ msgBuilder.handle(frame);
+ if (frame.getEof() && frame.getEos()) {//end of frameset
+ 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)
+{
+ completed.add(msg->getCommandId());
+ if (msg->requiresAccept()) {
+ getProxy().getMessage010().accept(SequenceSet(msg->getCommandId()));
+ }
+}
+
+void SessionState::handle(AMQFrame& frame)
+{
+ received(frame);
+
+ SequenceNumber commandId;
+ try {
+ //TODO: make command handling more uniform, regardless of whether
+ //commands carry content. (For now, assume all single frame
+ //assemblies are non-content bearing and all content-bearing
+ //assemblies will have more than one frame):
+ if (frame.getBof() && frame.getEof()) {
+ handleCommand(frame.getMethod(), commandId);
+ } else {
+ handleContent(frame, commandId);
+ }
+ } catch(const SessionException& e) {
+ //TODO: better implementation of new exception handling mechanism
+
+ //0-10 final changes the types of exceptions, 'model layer'
+ //exceptions will all be session exceptions regardless of
+ //current channel/connection classification
+
+ AMQMethodBody* m = frame.getMethod();
+ if (m) {
+ getProxy().getExecution010().exception(e.code, commandId, m->amqpClassId(), m->amqpMethodId(), 0, e.what(), FieldTable());
+ } else {
+ getProxy().getExecution010().exception(e.code, commandId, 0, 0, 0, e.what(), FieldTable());
+ }
+ handler->destroy();
+ }
+}
+
+DeliveryId SessionState::deliver(QueuedMessage& msg, DeliveryToken::shared_ptr token)
+{
+ uint32_t maxFrameSize = getConnection().getFrameMax();
+ MessageDelivery::deliver(msg, getProxy().getHandler(), nextOut, token, maxFrameSize);
+ return nextOut++;
+}
+
+void SessionState::sendCompletion()
+{
+ handler->sendCompletion();
+}
+
+void SessionState::complete(const SequenceSet& commands)
+{
+ knownCompleted.add(commands);
+ commands.for_each(ackOp);
+}
+
+
+}} // namespace qpid::broker
diff --git a/qpid/cpp/src/qpid/broker/SessionState.h b/qpid/cpp/src/qpid/broker/SessionState.h
new file mode 100644
index 0000000000..4fc2ae4cc5
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/SessionState.h
@@ -0,0 +1,159 @@
+#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/framing/Uuid.h"
+#include "qpid/framing/FrameHandler.h"
+#include "qpid/framing/SessionState.h"
+#include "qpid/framing/SequenceSet.h"
+#include "qpid/framing/ProtocolVersion.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Time.h"
+#include "qpid/management/Manageable.h"
+#include "qpid/management/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 sessions handler chains, which may
+ * themselves have state.
+ */
+class SessionState : public framing::SessionState,
+ public SessionContext,
+ public DeliveryAdapter,
+ public management::Manageable
+{
+ public:
+ ~SessionState();
+ bool isAttached() const { return handler; }
+
+ void detach();
+ void attach(SessionHandler& handler);
+
+
+ SessionHandler* getHandler();
+
+ /** @pre isAttached() */
+ framing::AMQP_ClientProxy& getProxy();
+
+ /** @pre isAttached() */
+ ConnectionState& getConnection();
+ bool isLocal(const ConnectionToken* t) const;
+
+ uint32_t getTimeout() const { return timeout; }
+ void setTimeout(uint32_t t) { timeout = t; }
+
+ Broker& getBroker() { return broker; }
+ framing::ProtocolVersion getVersion() const { return version; }
+
+ /** OutputControl **/
+ void activateOutput();
+
+ void handle(framing::AMQFrame& frame);
+
+ void complete(const framing::SequenceSet& ranges);
+ void sendCompletion();
+
+ //delivery adapter methods:
+ DeliveryId deliver(QueuedMessage& msg, DeliveryToken::shared_ptr token);
+
+ // Manageable entry points
+ management::ManagementObject::shared_ptr GetManagementObject (void) const;
+ management::Manageable::status_t
+ ManagementMethod (uint32_t methodId, management::Args& args);
+
+ // Normally SessionManager creates sessions.
+ SessionState(SessionManager*,
+ SessionHandler* out,
+ uint32_t timeout,
+ uint32_t ackInterval);
+
+
+ framing::SequenceSet completed;
+ framing::SequenceSet knownCompleted;
+ framing::SequenceNumber nextIn;
+ framing::SequenceNumber nextOut;
+
+ private:
+ typedef boost::function<void(DeliveryId, DeliveryId)> RangedOperation;
+
+ SessionManager* factory;
+ SessionHandler* handler;
+ framing::Uuid id;
+ uint32_t timeout;
+ sys::AbsTime expiry; // Used by SessionManager.
+ Broker& broker;
+ framing::ProtocolVersion version;
+ sys::Mutex lock;
+
+ SemanticState semanticState;
+ SessionAdapter adapter;
+ MessageBuilder msgBuilder;
+ IncompleteMessageList incomplete;
+
+ RangedOperation ackOp;
+ IncompleteMessageList::CompletionListener enqueuedOp;
+
+ management::Session::shared_ptr mgmtObject;
+ void handleCommand(framing::AMQMethodBody* method, framing::SequenceNumber& id);
+ void handleContent(framing::AMQFrame& frame, framing::SequenceNumber& id);
+ void enqueued(boost::intrusive_ptr<Message> msg);
+
+ 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/qpid/cpp/src/qpid/broker/System.cpp b/qpid/cpp/src/qpid/broker/System.cpp
new file mode 100644
index 0000000000..87d5185b97
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/System.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 "System.h"
+#include "qpid/management/ManagementAgent.h"
+#include <sys/utsname.h>
+
+using namespace qpid::broker;
+using qpid::management::ManagementAgent;
+
+System::System ()
+{
+ ManagementAgent::shared_ptr agent = ManagementAgent::getAgent ();
+
+ if (agent.get () != 0)
+ {
+ mgmtObject = management::System::shared_ptr
+ (new management::System (this, "host"));
+ struct utsname _uname;
+ if (uname (&_uname) == 0)
+ {
+ mgmtObject->set_osName (std::string (_uname.sysname));
+ mgmtObject->set_nodeName (std::string (_uname.nodename));
+ mgmtObject->set_release (std::string (_uname.release));
+ mgmtObject->set_version (std::string (_uname.version));
+ mgmtObject->set_machine (std::string (_uname.machine));
+ }
+
+ agent->addObject (mgmtObject, 3, 0);
+ }
+}
+
diff --git a/qpid/cpp/src/qpid/broker/System.h b/qpid/cpp/src/qpid/broker/System.h
new file mode 100644
index 0000000000..a1a710f2b2
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/System.h
@@ -0,0 +1,51 @@
+#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 "qpid/management/System.h"
+#include <boost/shared_ptr.hpp>
+
+namespace qpid {
+namespace broker {
+
+class System : public management::Manageable
+{
+ private:
+
+ management::System::shared_ptr mgmtObject;
+
+ public:
+
+ typedef boost::shared_ptr<System> shared_ptr;
+
+ System ();
+
+ management::ManagementObject::shared_ptr GetManagementObject (void) const
+ { return mgmtObject; }
+
+ management::Manageable::status_t ManagementMethod (uint32_t, management::Args&)
+ { return management::Manageable::STATUS_OK; }
+};
+
+}}
+
+#endif /*!_BrokerSystem_*/
diff --git a/qpid/cpp/src/qpid/broker/Timer.cpp b/qpid/cpp/src/qpid/broker/Timer.cpp
new file mode 100644
index 0000000000..9005a7cd6e
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/Timer.cpp
@@ -0,0 +1,103 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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();
+ 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/qpid/cpp/src/qpid/broker/Timer.h b/qpid/cpp/src/qpid/broker/Timer.h
new file mode 100644
index 0000000000..f702f0f32d
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/broker/TopicExchange.cpp b/qpid/cpp/src/qpid/broker/TopicExchange.cpp
new file mode 100644
index 0000000000..1c4fa2ea7a
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/TopicExchange.cpp
@@ -0,0 +1,242 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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;
+
+// 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.
+
+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 = 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;
+}
+
+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: Ineficient 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.get() != 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.get() != 0)
+ mgmtExchange->set_type (typeName);
+}
+
+bool TopicExchange::bind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* /*args*/){
+ RWlock::ScopedWlock l(lock);
+ TopicPattern routingPattern(routingKey);
+ if (isBound(queue, routingPattern)) {
+ return false;
+ } else {
+ Binding::shared_ptr binding (new Binding (routingKey, queue, this));
+ bindings[routingPattern].push_back(binding);
+ if (mgmtExchange.get() != 0) {
+ mgmtExchange->inc_bindings ();
+ dynamic_pointer_cast<management::Queue>(queue->GetManagementObject())->inc_bindings();
+ }
+ 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));
+ Binding::vector& qv(bi->second);
+ if (bi == bindings.end()) return 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);
+ if(qv.empty()) bindings.erase(bi);
+ if (mgmtExchange.get() != 0) {
+ mgmtExchange->dec_bindings ();
+ dynamic_pointer_cast<management::Queue>(queue->GetManagementObject())->dec_bindings();
+ }
+ 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);
+ 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*/){
+ RWlock::ScopedRlock l(lock);
+ uint32_t count(0);
+ Tokens tokens(routingKey);
+
+ for (BindingMap::iterator i = bindings.begin(); i != bindings.end(); ++i) {
+ if (i->first.match(tokens)) {
+ Binding::vector& qv(i->second);
+ for(Binding::vector::iterator j = qv.begin(); j != qv.end(); j++, count++){
+ msg.deliverTo((*j)->queue);
+ if ((*j)->mgmtBinding.get() != 0)
+ (*j)->mgmtBinding->inc_msgMatched ();
+ }
+ }
+ }
+
+ if (mgmtExchange.get() != 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);
+ 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/qpid/cpp/src/qpid/broker/TopicExchange.h b/qpid/cpp/src/qpid/broker/TopicExchange.h
new file mode 100644
index 0000000000..2e107142b7
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/TopicExchange.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.
+ *
+ */
+#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);
+
+ 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{
+ typedef std::map<TopicPattern, Binding::vector> 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();
+};
+
+
+
+}
+}
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/TransactionalStore.h b/qpid/cpp/src/qpid/broker/TransactionalStore.h
new file mode 100644
index 0000000000..2a2bac0c51
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/broker/TxAccept.cpp b/qpid/cpp/src/qpid/broker/TxAccept.cpp
new file mode 100644
index 0000000000..634d066ecc
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/TxAccept.cpp
@@ -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.
+ *
+ */
+#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::AccumulatedAck;
+
+TxAccept::TxAccept(AccumulatedAck& _acked, std::list<DeliveryRecord>& _unacked) :
+ acked(_acked), unacked(_unacked) {}
+
+bool TxAccept::prepare(TransactionContext* ctxt) throw()
+{
+ try{
+ //dequeue messages from their respective queues:
+ for (ack_iterator i = unacked.begin(); i != unacked.end(); i++) {
+ if (i->coveredBy(&acked)) {
+ i->dequeue(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()
+{
+ for (ack_iterator i = unacked.begin(); i != unacked.end(); i++) {
+ if (i->coveredBy(&acked)) i->setEnded();
+ }
+
+ unacked.remove_if(mem_fun_ref(&DeliveryRecord::isRedundant));
+}
+
+void TxAccept::rollback() throw() {}
diff --git a/qpid/cpp/src/qpid/broker/TxAccept.h b/qpid/cpp/src/qpid/broker/TxAccept.h
new file mode 100644
index 0000000000..011acf5d9e
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/TxAccept.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 _TxAccept_
+#define _TxAccept_
+
+#include <algorithm>
+#include <functional>
+#include <list>
+#include "qpid/framing/AccumulatedAck.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{
+ framing::AccumulatedAck& acked;
+ std::list<DeliveryRecord>& unacked;
+
+ public:
+ /**
+ * @param acked a representation of the accumulation of
+ * acks received
+ * @param unacked the record of delivered messages
+ */
+ TxAccept(framing::AccumulatedAck& acked, std::list<DeliveryRecord>& unacked);
+ virtual bool prepare(TransactionContext* ctxt) throw();
+ virtual void commit() throw();
+ virtual void rollback() throw();
+ virtual ~TxAccept(){}
+ };
+ }
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/TxAck.cpp b/qpid/cpp/src/qpid/broker/TxAck.cpp
new file mode 100644
index 0000000000..40b9b0ff33
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/TxAck.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 "TxAck.h"
+#include "qpid/log/Statement.h"
+
+using std::bind1st;
+using std::bind2nd;
+using std::mem_fun_ref;
+using namespace qpid::broker;
+using qpid::framing::AccumulatedAck;
+
+TxAck::TxAck(AccumulatedAck& _acked, std::list<DeliveryRecord>& _unacked) :
+ acked(_acked), unacked(_unacked){
+
+}
+
+bool TxAck::prepare(TransactionContext* ctxt) throw(){
+ try{
+ //dequeue all acked messages from their queues
+ for (ack_iterator i = unacked.begin(); i != unacked.end(); i++) {
+ if (i->coveredBy(&acked)) {
+ i->dequeue(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 TxAck::commit() throw(){
+ //remove all acked records from the list
+ unacked.remove_if(bind2nd(mem_fun_ref(&DeliveryRecord::coveredBy), &acked));
+}
+
+void TxAck::rollback() throw(){
+}
diff --git a/qpid/cpp/src/qpid/broker/TxAck.h b/qpid/cpp/src/qpid/broker/TxAck.h
new file mode 100644
index 0000000000..c8383b6314
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/TxAck.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 _TxAck_
+#define _TxAck_
+
+#include <algorithm>
+#include <functional>
+#include <list>
+#include "qpid/framing/AccumulatedAck.h"
+#include "DeliveryRecord.h"
+#include "TxOp.h"
+
+namespace qpid {
+ namespace broker {
+ /**
+ * Defines the transactional behaviour for acks received by a
+ * transactional channel.
+ */
+ class TxAck : public TxOp{
+ framing::AccumulatedAck& acked;
+ std::list<DeliveryRecord>& unacked;
+
+ public:
+ /**
+ * @param acked a representation of the accumulation of
+ * acks received
+ * @param unacked the record of delivered messages
+ */
+ TxAck(framing::AccumulatedAck& acked, std::list<DeliveryRecord>& unacked);
+ virtual bool prepare(TransactionContext* ctxt) throw();
+ virtual void commit() throw();
+ virtual void rollback() throw();
+ virtual ~TxAck(){}
+ };
+ }
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/TxBuffer.cpp b/qpid/cpp/src/qpid/broker/TxBuffer.cpp
new file mode 100644
index 0000000000..5b5b00e929
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/TxBuffer.cpp
@@ -0,0 +1,67 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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 <boost/mem_fn.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()
+{
+ for_each(ops.begin(), ops.end(), mem_fn(&TxOp::commit));
+ ops.clear();
+}
+
+void TxBuffer::rollback()
+{
+ 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)
+{
+ std::auto_ptr<TransactionContext> ctxt;
+ if(store) ctxt = store->begin();
+ if (prepare(ctxt.get())) {
+ if(store) store->commit(*ctxt);
+ commit();
+ return true;
+ } else {
+ if(store) store->abort(*ctxt);
+ rollback();
+ return false;
+ }
+}
diff --git a/qpid/cpp/src/qpid/broker/TxBuffer.h b/qpid/cpp/src/qpid/broker/TxBuffer.h
new file mode 100644
index 0000000000..361c47e92c
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/TxBuffer.h
@@ -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.
+ *
+ */
+#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);
+ };
+ }
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/TxOp.h b/qpid/cpp/src/qpid/broker/TxOp.h
new file mode 100644
index 0000000000..e687c437cc
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/TxOp.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.
+ *
+ */
+#ifndef _TxOp_
+#define _TxOp_
+
+#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(){}
+ };
+ }
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/TxPublish.cpp b/qpid/cpp/src/qpid/broker/TxPublish.cpp
new file mode 100644
index 0000000000..1a8630eb54
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/TxPublish.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 "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(...){
+ QPID_LOG(error, "Failed to prepare");
+ return false;
+ }
+}
+
+void TxPublish::commit() throw(){
+ for_each(queues.begin(), queues.end(), Commit(msg));
+}
+
+void TxPublish::rollback() throw(){
+}
+
+void TxPublish::deliverTo(Queue::shared_ptr& 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()(Queue::shared_ptr& 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()(Queue::shared_ptr& queue){
+ queue->process(msg);
+}
+
+uint64_t TxPublish::contentSize ()
+{
+ return msg->contentSize ();
+}
diff --git a/qpid/cpp/src/qpid/broker/TxPublish.h b/qpid/cpp/src/qpid/broker/TxPublish.h
new file mode 100644
index 0000000000..680e0c7546
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/TxPublish.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 _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()(Queue::shared_ptr& queue);
+ };
+
+ class Commit{
+ boost::intrusive_ptr<Message>& msg;
+ public:
+ Commit(boost::intrusive_ptr<Message>& msg);
+ void operator()(Queue::shared_ptr& 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 void deliverTo(Queue::shared_ptr& queue);
+
+ virtual ~TxPublish(){}
+
+ uint64_t contentSize();
+ };
+ }
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/broker/Vhost.cpp b/qpid/cpp/src/qpid/broker/Vhost.cpp
new file mode 100644
index 0000000000..06a8c8eca3
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/Vhost.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 "Vhost.h"
+#include "qpid/management/ManagementAgent.h"
+
+using namespace qpid::broker;
+using qpid::management::ManagementAgent;
+
+Vhost::Vhost (management::Manageable* parentBroker)
+{
+ if (parentBroker != 0)
+ {
+ ManagementAgent::shared_ptr agent = ManagementAgent::getAgent ();
+
+ if (agent.get () != 0)
+ {
+ mgmtObject = management::Vhost::shared_ptr
+ (new management::Vhost (this, parentBroker, "/"));
+ agent->addObject (mgmtObject, 2, 0);
+ }
+ }
+}
+
diff --git a/qpid/cpp/src/qpid/broker/Vhost.h b/qpid/cpp/src/qpid/broker/Vhost.h
new file mode 100644
index 0000000000..b702dcebf0
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/Vhost.h
@@ -0,0 +1,51 @@
+#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 "qpid/management/Vhost.h"
+#include <boost/shared_ptr.hpp>
+
+namespace qpid {
+namespace broker {
+
+class Vhost : public management::Manageable
+{
+ private:
+
+ management::Vhost::shared_ptr mgmtObject;
+
+ public:
+
+ typedef boost::shared_ptr<Vhost> shared_ptr;
+
+ Vhost (management::Manageable* parentBroker);
+
+ management::ManagementObject::shared_ptr GetManagementObject (void) const
+ { return mgmtObject; }
+
+ management::Manageable::status_t ManagementMethod (uint32_t, management::Args&)
+ { return management::Manageable::STATUS_OK; }
+};
+
+}}
+
+#endif /*!_Vhost_*/
diff --git a/qpid/cpp/src/qpid/client/AckMode.h b/qpid/cpp/src/qpid/client/AckMode.h
new file mode 100644
index 0000000000..944fba655d
--- /dev/null
+++ b/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 acknowledgements 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/qpid/cpp/src/qpid/client/AckPolicy.h b/qpid/cpp/src/qpid/client/AckPolicy.h
new file mode 100644
index 0000000000..af17539ebe
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/AckPolicy.h
@@ -0,0 +1,56 @@
+#ifndef QPID_CLIENT_ACKPOLICY_H
+#define QPID_CLIENT_ACKPOLICY_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 {
+
+/**
+ * Policy for automatic acknowledgement of messages.
+ *
+ * \ingroup clientapi
+ */
+class AckPolicy
+{
+ size_t interval;
+ size_t count;
+
+ public:
+ /**
+ *@param n: acknowledge every n messages.
+ *n==0 means no automatick acknowledgement.
+ */
+ AckPolicy(size_t n=1) : interval(n), count(n) {}
+
+ void ack(const Message& msg) {
+ if (!interval) return;
+ bool send=(--count==0);
+ msg.acknowledge(true, send);
+ if (send) count = interval;
+ }
+};
+
+}} // namespace qpid::client
+
+
+
+#endif /*!QPID_CLIENT_ACKPOLICY_H*/
diff --git a/qpid/cpp/src/qpid/client/ChainableFrameHandler.h b/qpid/cpp/src/qpid/client/ChainableFrameHandler.h
new file mode 100644
index 0000000000..29e16d53dc
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/client/Channel.cpp b/qpid/cpp/src/qpid/client/Channel.cpp
new file mode 100644
index 0000000000..4af69c8552
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/Channel.cpp
@@ -0,0 +1,268 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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 <iostream>
+#include <sstream>
+#include "Channel.h"
+#include "qpid/sys/Monitor.h"
+#include "Message.h"
+#include "Connection.h"
+#include "Demux.h"
+#include "FutureResponse.h"
+#include "MessageListener.h"
+#include "MessageQueue.h"
+#include <boost/format.hpp>
+#include <boost/bind.hpp>
+#include "qpid/framing/all_method_bodies.h"
+
+using namespace std;
+using namespace boost;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+namespace qpid{
+namespace client{
+using namespace arg;
+
+const std::string empty;
+
+class ScopedSync
+{
+ Session& session;
+ public:
+ ScopedSync(Session& s, bool enabled = true) : session(s) { session.setSynchronous(enabled); }
+ ~ScopedSync() { session.setSynchronous(false); }
+};
+
+Channel::Channel(bool _transactional, u_int16_t _prefetch) :
+ prefetch(_prefetch), transactional(_transactional), running(false),
+ uniqueId(true)/*could eventually be the session id*/, nameCounter(0), active(false)
+{
+}
+
+Channel::~Channel()
+{
+ join();
+}
+
+void Channel::open(const Session& s)
+{
+ Mutex::ScopedLock l(stopLock);
+ if (isOpen())
+ throw ChannelBusyException();
+ active = true;
+ session = s;
+ if(isTransactional()) {
+ session.txSelect();
+ }
+}
+
+bool Channel::isOpen() const {
+ Mutex::ScopedLock l(stopLock);
+ return active;
+}
+
+void Channel::setPrefetch(uint32_t _prefetch){
+ prefetch = _prefetch;
+}
+
+void Channel::declareExchange(Exchange& _exchange, bool synch){
+ ScopedSync s(session, synch);
+ session.exchangeDeclare(exchange=_exchange.getName(), type=_exchange.getType());
+}
+
+void Channel::deleteExchange(Exchange& _exchange, bool synch){
+ ScopedSync s(session, synch);
+ session.exchangeDelete(exchange=_exchange.getName(), ifUnused=false);
+}
+
+void Channel::declareQueue(Queue& _queue, bool synch){
+ if (_queue.getName().empty()) {
+ stringstream uniqueName;
+ uniqueName << uniqueId << "-queue-" << ++nameCounter;
+ _queue.setName(uniqueName.str());
+ }
+
+ ScopedSync s(session, synch);
+ session.queueDeclare(queue=_queue.getName(), passive=false/*passive*/, durable=_queue.isDurable(),
+ exclusive=_queue.isExclusive(), autoDelete=_queue.isAutoDelete());
+
+}
+
+void Channel::deleteQueue(Queue& _queue, bool ifunused, bool ifempty, bool synch){
+ ScopedSync s(session, synch);
+ session.queueDelete(queue=_queue.getName(), ifUnused=ifunused, ifEmpty=ifempty);
+}
+
+void Channel::bind(const Exchange& exchange, const Queue& queue, const std::string& key, const FieldTable& args, bool synch){
+ string e = exchange.getName();
+ string q = queue.getName();
+ ScopedSync s(session, synch);
+ session.queueBind(0, q, e, key, args);
+}
+
+void Channel::commit(){
+ session.txCommit();
+}
+
+void Channel::rollback(){
+ session.txRollback();
+}
+
+void Channel::consume(
+ Queue& _queue, const std::string& tag, MessageListener* listener,
+ AckMode ackMode, bool noLocal, bool synch, const FieldTable* fields) {
+
+ if (tag.empty()) {
+ throw Exception("A tag must be specified for a consumer.");
+ }
+ {
+ Mutex::ScopedLock l(lock);
+ ConsumerMap::iterator i = consumers.find(tag);
+ if (i != consumers.end())
+ throw NotAllowedException(QPID_MSG("Consumer already exists with tag " << tag ));
+ Consumer& c = consumers[tag];
+ c.listener = listener;
+ c.ackMode = ackMode;
+ c.count = 0;
+ }
+ uint8_t confirmMode = ackMode == NO_ACK ? 0 : 1;
+ ScopedSync s(session, synch);
+ session.messageSubscribe(0, _queue.getName(), tag, noLocal,
+ confirmMode, 0/*pre-acquire*/,
+ false, fields ? *fields : FieldTable());
+ if (!prefetch) {
+ session.messageFlowMode(tag, 0/*credit based*/);
+ }
+
+ //allocate some credit:
+ session.messageFlow(tag, 1/*BYTES*/, 0xFFFFFFFF);
+ session.messageFlow(tag, 0/*MESSAGES*/, prefetch ? prefetch : 0xFFFFFFFF);
+}
+
+void Channel::cancel(const std::string& tag, bool synch) {
+ Consumer c;
+ {
+ Mutex::ScopedLock l(lock);
+ ConsumerMap::iterator i = consumers.find(tag);
+ if (i == consumers.end())
+ return;
+ c = i->second;
+ consumers.erase(i);
+ }
+ ScopedSync s(session, synch);
+ session.messageCancel(tag);
+}
+
+bool Channel::get(Message& msg, const Queue& _queue, AckMode ackMode) {
+ string tag = "get-handler";
+ ScopedDivert handler(tag, session.getExecution().getDemux());
+ Demux::QueuePtr incoming = handler.getQueue();
+
+ session.messageSubscribe(destination=tag, queue=_queue.getName(), confirmMode=(ackMode == NO_ACK ? 0 : 1));
+ session.messageFlow(tag, 1/*BYTES*/, 0xFFFFFFFF);
+ session.messageFlow(tag, 0/*MESSAGES*/, 1);
+ Completion status = session.messageFlush(tag);
+ status.sync();
+ session.messageCancel(tag);
+
+ FrameSet::shared_ptr p;
+ if (incoming->tryPop(p)) {
+ msg.populate(*p);
+ if (ackMode == AUTO_ACK) msg.acknowledge(session, false, true);
+ return true;
+ }
+ else
+ return false;
+}
+
+void Channel::publish(Message& msg, const Exchange& exchange,
+ const std::string& routingKey,
+ bool mandatory, bool /*?TODO-restore immediate?*/) {
+
+ msg.getDeliveryProperties().setRoutingKey(routingKey);
+ msg.getDeliveryProperties().setDiscardUnroutable(!mandatory);
+ session.messageTransfer(destination=exchange.getName(), content=msg);
+}
+
+void Channel::close()
+{
+ session.close();
+ {
+ Mutex::ScopedLock l(stopLock);
+ active = false;
+ }
+ stop();
+}
+
+void Channel::start(){
+ running = true;
+ dispatcher = Thread(*this);
+}
+
+void Channel::stop() {
+ gets.close();
+ join();
+}
+
+void Channel::join() {
+ Mutex::ScopedLock l(stopLock);
+ if(running && dispatcher.id()) {
+ dispatcher.join();
+ running = false;
+ }
+}
+
+void Channel::dispatch(FrameSet& content, const std::string& destination)
+{
+ ConsumerMap::iterator i = consumers.find(destination);
+ if (i != consumers.end()) {
+ Message msg;
+ msg.populate(content);
+ MessageListener* listener = i->second.listener;
+ listener->received(msg);
+ if (isOpen() && i->second.ackMode != CLIENT_ACK) {
+ bool send = i->second.ackMode == AUTO_ACK
+ || (prefetch && ++(i->second.count) > (prefetch / 2));
+ if (send) i->second.count = 0;
+ session.getExecution().completed(content.getId(), true, send);
+ }
+ } else {
+ QPID_LOG(warning, "Dropping message for unrecognised consumer: " << destination);
+ }
+}
+
+void Channel::run() {
+ try {
+ while (true) {
+ FrameSet::shared_ptr content = session.get();
+ //need to dispatch this to the relevant listener:
+ if (content->isA<MessageTransferBody>()) {
+ dispatch(*content, content->as<MessageTransferBody>()->getDestination());
+ } else {
+ QPID_LOG(warning, "Dropping unsupported message type: " << content->getMethod());
+ }
+ }
+ } catch (const ClosedException&) {}
+}
+
+}}
+
diff --git a/qpid/cpp/src/qpid/client/Channel.h b/qpid/cpp/src/qpid/client/Channel.h
new file mode 100644
index 0000000000..2cda97dc63
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/Channel.h
@@ -0,0 +1,316 @@
+#ifndef _client_Channel_h
+#define _client_Channel_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 <boost/scoped_ptr.hpp>
+#include "qpid/framing/amqp_framing.h"
+#include "qpid/framing/Uuid.h"
+#include "Exchange.h"
+#include "Message.h"
+#include "Queue.h"
+#include "ConnectionImpl.h"
+#include "qpid/client/Session.h"
+#include "qpid/Exception.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/sys/Thread.h"
+#include "AckMode.h"
+
+namespace qpid {
+
+namespace framing {
+class ChannelCloseBody;
+class AMQMethodBody;
+}
+
+namespace client {
+
+class Connection;
+class MessageChannel;
+class MessageListener;
+class ReturnedMessageHandler;
+
+/**
+ * THIS CLASS IS DEPRECATED AND WILL BE SHORTLY REMOVED
+ *
+ * Represents an AMQP channel, i.e. loosely a session of work. It
+ * is through a channel that most of the AMQP 'methods' are
+ * exposed.
+ *
+ */
+class Channel : private sys::Runnable
+{
+ private:
+ struct Consumer{
+ MessageListener* listener;
+ AckMode ackMode;
+ uint32_t count;
+ };
+ typedef std::map<std::string, Consumer> ConsumerMap;
+
+ mutable sys::Mutex lock;
+ sys::Thread dispatcher;
+
+ uint32_t prefetch;
+ const bool transactional;
+ framing::ProtocolVersion version;
+
+ mutable sys::Mutex stopLock;
+ bool running;
+
+ ConsumerMap consumers;
+ Session session;
+ framing::ChannelId channelId;
+ sys::BlockingQueue<framing::FrameSet::shared_ptr> gets;
+ framing::Uuid uniqueId;
+ uint32_t nameCounter;
+ bool active;
+
+ void stop();
+
+ void open(const Session& session);
+ void closeInternal();
+ void join();
+
+ void dispatch(framing::FrameSet& msg, const std::string& destination);
+
+ friend class Connection;
+
+ public:
+ /**
+ * Creates a channel object.
+ *
+ * @param transactional if true, the publishing and acknowledgement
+ * of messages will be transactional and can be committed or
+ * aborted in atomic units (@see commit(), @see rollback())
+ *
+ * @param prefetch specifies the number of unacknowledged
+ * messages the channel is willing to have sent to it
+ * asynchronously
+ */
+ Channel(bool transactional = false, u_int16_t prefetch = 0);
+
+ ~Channel();
+
+ /**
+ * Declares an exchange.
+ *
+ * In AMQP Exchanges are the destinations to which messages
+ * are published. They have Queues bound to them and route
+ * messages they receive to those queues. The routing rules
+ * depend on the type of the exchange.
+ *
+ * @param exchange an Exchange object representing the
+ * exchange to declare
+ *
+ * @param synch if true this call will block until a response
+ * is received from the broker
+ */
+ void declareExchange(Exchange& exchange, bool synch = true);
+ /**
+ * Deletes an exchange
+ *
+ * @param exchange an Exchange object representing the exchange to delete
+ *
+ * @param synch if true this call will block until a response
+ * is received from the broker
+ */
+ void deleteExchange(Exchange& exchange, bool synch = true);
+ /**
+ * Declares a Queue
+ *
+ * @param queue a Queue object representing the queue to declare
+ *
+ * @param synch if true this call will block until a response
+ * is received from the broker
+ */
+ void declareQueue(Queue& queue, bool synch = true);
+ /**
+ * Deletes a Queue
+ *
+ * @param queue a Queue object representing the queue to delete
+ *
+ * @param synch if true this call will block until a response
+ * is received from the broker
+ */
+ void deleteQueue(Queue& queue, bool ifunused = false, bool ifempty = false, bool synch = true);
+ /**
+ * Binds a queue to an exchange. The exact semantics of this
+ * (in particular how 'routing keys' and 'binding arguments'
+ * are used) depends on the type of the exchange.
+ *
+ * @param exchange an Exchange object representing the
+ * exchange to bind to
+ *
+ * @param queue a Queue object representing the queue to be
+ * bound
+ *
+ * @param key the 'routing key' for the binding
+ *
+ * @param args the 'binding arguments' for the binding
+ *
+ * @param synch if true this call will block until a response
+ * is received from the broker
+ */
+ void bind(const Exchange& exchange, const Queue& queue,
+ const std::string& key,
+ const framing::FieldTable& args=framing::FieldTable(),
+ bool synch = true);
+
+ /**
+ * For a transactional channel this will commit all
+ * publications and acknowledgements since the last commit (or
+ * the channel was opened if there has been no previous
+ * commit). This will cause published messages to become
+ * available to consumers and acknowledged messages to be
+ * consumed and removed from the queues they were dispatched
+ * from.
+ *
+ * Transactionailty of a channel is specified when the channel
+ * object is created (@see Channel()).
+ */
+ void commit();
+
+ /**
+ * For a transactional channel, this will rollback any
+ * publications or acknowledgements. It will be as if the
+ * ppblished messages were never sent and the acknowledged
+ * messages were never consumed.
+ */
+ void rollback();
+
+ /**
+ * Change the prefetch in use.
+ */
+ void setPrefetch(uint32_t prefetch);
+
+ uint32_t getPrefetch() { return prefetch; }
+
+ /**
+ * Start message dispatching on a new thread
+ */
+ void start();
+
+ /**
+ * Close the channel. Closing a channel that is not open has no
+ * effect.
+ */
+ void close();
+
+ /** True if the channel is transactional */
+ bool isTransactional() { return transactional; }
+
+ /** True if the channel is open */
+ bool isOpen() const;
+
+ /** Return the protocol version */
+ framing::ProtocolVersion getVersion() const { return version ; }
+
+ /**
+ * Creates a 'consumer' for a queue. Messages in (or arriving
+ * at) that queue will be delivered to consumers
+ * asynchronously.
+ *
+ * @param queue a Queue instance representing the queue to
+ * consume from
+ *
+ * @param tag an identifier to associate with the consumer
+ * that can be used to cancel its subscription (if empty, this
+ * will be assigned by the broker)
+ *
+ * @param listener a pointer to an instance of an
+ * implementation of the MessageListener interface. Messages
+ * received from this queue for this consumer will result in
+ * invocation of the received() method on the listener, with
+ * the message itself passed in.
+ *
+ * @param ackMode the mode of acknowledgement that the broker
+ * should assume for this consumer. @see AckMode
+ *
+ * @param noLocal if true, this consumer will not be sent any
+ * message published by this connection
+ *
+ * @param synch if true this call will block until a response
+ * is received from the broker
+ */
+ void consume(
+ Queue& queue, const std::string& tag, MessageListener* listener,
+ AckMode ackMode = NO_ACK, bool noLocal = false, bool synch = true,
+ const framing::FieldTable* fields = 0);
+
+ /**
+ * Cancels a subscription previously set up through a call to consume().
+ *
+ * @param tag the identifier used (or assigned) in the consume
+ * request that set up the subscription to be cancelled.
+ *
+ * @param synch if true this call will block until a response
+ * is received from the broker
+ */
+ void cancel(const std::string& tag, bool synch = true);
+ /**
+ * Synchronous pull of a message from a queue.
+ *
+ * @param msg a message object that will contain the message
+ * headers and content if the call completes.
+ *
+ * @param queue the queue to consume from
+ *
+ * @param ackMode the acknowledgement mode to use (@see
+ * AckMode)
+ *
+ * @return true if a message was succcessfully dequeued from
+ * the queue, false if the queue was empty.
+ */
+ bool get(Message& msg, const Queue& queue, AckMode ackMode = NO_ACK);
+
+ /**
+ * Publishes (i.e. sends a message to the broker).
+ *
+ * @param msg the message to publish
+ *
+ * @param exchange the exchange to publish the message to
+ *
+ * @param routingKey the routing key to publish with
+ *
+ * @param mandatory if true and the exchange to which this
+ * publish is directed has no matching bindings, the message
+ * will be returned (see setReturnedMessageHandler()).
+ *
+ * @param immediate if true and there is no consumer to
+ * receive this message on publication, the message will be
+ * returned (see setReturnedMessageHandler()).
+ */
+ void publish(Message& msg, const Exchange& exchange,
+ const std::string& routingKey,
+ bool mandatory = false, bool immediate = false);
+
+ /**
+ * Deliver incoming messages to the appropriate MessageListener.
+ */
+ void run();
+};
+
+}}
+
+#endif /*!_client_Channel_h*/
diff --git a/qpid/cpp/src/qpid/client/Completion.h b/qpid/cpp/src/qpid/client/Completion.h
new file mode 100644
index 0000000000..4d324aaf28
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/Completion.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 _Completion_
+#define _Completion_
+
+#include <boost/shared_ptr.hpp>
+#include "Future.h"
+#include "SessionCore.h"
+
+namespace qpid {
+namespace client {
+
+class Completion
+{
+protected:
+ Future future;
+ shared_ptr<SessionCore> session;
+
+public:
+ Completion() {}
+
+ Completion(Future f, shared_ptr<SessionCore> s) : future(f), session(s) {}
+
+ void sync()
+ {
+ future.sync(*session);
+ }
+
+ void wait()
+ {
+ future.wait(*session);
+ }
+
+ bool isComplete() {
+ return future.isComplete(*session);
+ }
+
+ bool isCompleteUpTo() {
+ return future.isCompleteUpTo(*session);
+ }
+};
+
+}}
+
+#endif
diff --git a/qpid/cpp/src/qpid/client/CompletionTracker.cpp b/qpid/cpp/src/qpid/client/CompletionTracker.cpp
new file mode 100644
index 0000000000..76ea9dec51
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/CompletionTracker.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 "CompletionTracker.h"
+#include <algorithm>
+
+using qpid::client::CompletionTracker;
+using namespace qpid::framing;
+using namespace boost;
+
+namespace
+{
+const std::string empty;
+}
+
+CompletionTracker::CompletionTracker() : closed(false) {}
+CompletionTracker::CompletionTracker(const SequenceNumber& m) : mark(m) {}
+
+void CompletionTracker::close()
+{
+ sys::Mutex::ScopedLock l(lock);
+ closed=true;
+ while (!listeners.empty()) {
+ Record r(listeners.front());
+ {
+ sys::Mutex::ScopedUnlock u(lock);
+ r.completed();
+ }
+ listeners.pop_front();
+ }
+}
+
+
+void CompletionTracker::completed(const SequenceNumber& _mark)
+{
+ sys::Mutex::ScopedLock l(lock);
+ mark = _mark;
+ while (!listeners.empty() && !(listeners.front().id > mark)) {
+ Record r(listeners.front());
+ listeners.pop_front();
+ {
+ sys::Mutex::ScopedUnlock u(lock);
+ r.completed();
+ }
+ }
+}
+
+void CompletionTracker::received(const SequenceNumber& id, const std::string& result)
+{
+ sys::Mutex::ScopedLock l(lock);
+ Listeners::iterator i = seek(id);
+ if (i != listeners.end() && i->id == id) {
+ i->received(result);
+ listeners.erase(i);
+ }
+}
+
+void CompletionTracker::listenForCompletion(const SequenceNumber& point, CompletionListener listener)
+{
+ if (!add(Record(point, listener))) {
+ listener();
+ }
+}
+
+void CompletionTracker::listenForResult(const SequenceNumber& point, ResultListener listener)
+{
+ if (!add(Record(point, listener))) {
+ listener(empty);
+ }
+}
+
+bool CompletionTracker::add(const Record& record)
+{
+ sys::Mutex::ScopedLock l(lock);
+ if (record.id <= mark || closed) {
+ return false;
+ } else {
+ //insert at the correct position
+ Listeners::iterator i = seek(record.id);
+ if (i == listeners.end()) i = listeners.begin();
+ listeners.insert(i, record);
+ return true;
+ }
+}
+
+CompletionTracker::Listeners::iterator CompletionTracker::seek(const framing::SequenceNumber& point)
+{
+ Listeners::iterator i = listeners.begin();
+ while (i != listeners.end() && i->id < point) i++;
+ return i;
+}
+
+
+void CompletionTracker::Record::completed()
+{
+ if (f) f();
+ else if(g) g(empty);//won't get a result if command is now complete
+}
+
+void CompletionTracker::Record::received(const std::string& result)
+{
+ if (g) g(result);
+}
diff --git a/qpid/cpp/src/qpid/client/CompletionTracker.h b/qpid/cpp/src/qpid/client/CompletionTracker.h
new file mode 100644
index 0000000000..55f7ff7531
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/CompletionTracker.h
@@ -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 <list>
+#include <boost/function.hpp>
+#include "qpid/framing/amqp_framing.h"
+#include "qpid/framing/SequenceNumber.h"
+#include "qpid/sys/Mutex.h"
+
+#ifndef _CompletionTracker_
+#define _CompletionTracker_
+
+namespace qpid {
+namespace client {
+
+class CompletionTracker
+{
+public:
+ typedef boost::function<void()> CompletionListener;
+ typedef boost::function<void(const std::string&)> ResultListener;
+
+ CompletionTracker();
+ CompletionTracker(const framing::SequenceNumber& mark);
+ void completed(const framing::SequenceNumber& mark);
+ void received(const framing::SequenceNumber& id, const std::string& result);
+ void listenForCompletion(const framing::SequenceNumber& point, CompletionListener l);
+ void listenForResult(const framing::SequenceNumber& point, ResultListener l);
+ void close();
+
+private:
+ struct Record
+ {
+ framing::SequenceNumber id;
+ CompletionListener f;
+ ResultListener g;
+
+ Record(const framing::SequenceNumber& _id, CompletionListener l) : id(_id), f(l) {}
+ Record(const framing::SequenceNumber& _id, ResultListener l) : id(_id), g(l) {}
+ void completed();
+ void received(const std::string& result);
+
+ };
+
+ typedef std::list<Record> Listeners;
+ bool closed;
+
+ sys::Mutex lock;
+ framing::SequenceNumber mark;
+ Listeners listeners;
+
+ bool add(const Record& r);
+ Listeners::iterator seek(const framing::SequenceNumber&);
+};
+
+}
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/client/Connection.cpp b/qpid/cpp/src/qpid/client/Connection.cpp
new file mode 100644
index 0000000000..872e04b3b5
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/Connection.cpp
@@ -0,0 +1,97 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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 <boost/format.hpp>
+#include <boost/bind.hpp>
+
+#include "Connection.h"
+#include "Channel.h"
+#include "Message.h"
+#include "SessionCore.h"
+#include "qpid/log/Logger.h"
+#include "qpid/log/Options.h"
+#include "qpid/log/Statement.h"
+#include "qpid/shared_ptr.h"
+#include <iostream>
+#include <sstream>
+#include <functional>
+
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+
+namespace qpid {
+namespace client {
+
+Connection::Connection(bool _debug, uint32_t _max_frame_size, framing::ProtocolVersion _version) :
+ channelIdCounter(0), version(_version),
+ max_frame_size(_max_frame_size),
+ isOpen(false),
+ impl(new ConnectionImpl(
+ shared_ptr<Connector>(new Connector(_version, _debug))))
+{}
+
+Connection::Connection(shared_ptr<Connector> c) :
+ channelIdCounter(0), version(framing::highestProtocolVersion),
+ max_frame_size(65535),
+ isOpen(false),
+ impl(new ConnectionImpl(c))
+{}
+
+Connection::~Connection(){ }
+
+void Connection::open(
+ const std::string& host, int port,
+ const std::string& uid, const std::string& pwd, const std::string& vhost)
+{
+ if (isOpen)
+ throw Exception(QPID_MSG("Channel object is already open"));
+
+ impl->open(host, port, uid, pwd, vhost);
+ isOpen = true;
+}
+
+void Connection::openChannel(Channel& channel) {
+ channel.open(newSession(ASYNC));
+}
+
+Session Connection::newSession(SynchronousMode sync,
+ uint32_t detachedLifetime)
+{
+ shared_ptr<SessionCore> core(
+ new SessionCore(impl, ++channelIdCounter, max_frame_size));
+ core->setSync(sync);
+ impl->addSession(core);
+ core->open(detachedLifetime);
+ return Session(core);
+}
+
+void Connection::resume(Session& session) {
+ session.impl->setChannel(++channelIdCounter);
+ impl->addSession(session.impl);
+ session.impl->resume(impl);
+}
+
+void Connection::close() {
+ impl->close();
+}
+
+}} // namespace qpid::client
diff --git a/qpid/cpp/src/qpid/client/Connection.h b/qpid/cpp/src/qpid/client/Connection.h
new file mode 100644
index 0000000000..81d9b972b6
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/Connection.h
@@ -0,0 +1,149 @@
+#ifndef _client_Connection_
+#define _client_Connection_
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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 "Channel.h"
+#include "ConnectionImpl.h"
+#include "qpid/client/Session.h"
+#include "qpid/framing/AMQP_HighestVersion.h"
+#include "qpid/framing/Uuid.h"
+
+namespace qpid {
+
+/**
+ * The client namespace contains all classes that make up a client
+ * implementation of the AMQP protocol. The key classes that form
+ * the basis of the client API to be used by applications are
+ * Connection and Channel.
+ */
+namespace client {
+
+/**
+ * \defgroup clientapi Application API for an AMQP client
+ */
+
+/**
+ * Represents a connection to an AMQP broker. All communication is
+ * initiated by establishing a connection, then opening one or
+ * more Channels over that connection.
+ *
+ * \ingroup clientapi
+ */
+class Connection
+{
+ framing::ChannelId channelIdCounter;
+ framing::ProtocolVersion version;
+ const uint32_t max_frame_size;
+ bool isOpen;
+ bool debug;
+
+ protected:
+ boost::shared_ptr<ConnectionImpl> impl;
+
+ public:
+ /**
+ * Creates a connection object, but does not open the
+ * connection.
+ *
+ * @param _version the version of the protocol to connect with
+ *
+ * @param debug turns on tracing for the connection
+ * (i.e. prints details of the frames sent and received to std
+ * out). Optional and defaults to false.
+ *
+ * @param max_frame_size the maximum frame size that the
+ * client will accept. Optional and defaults to 65535.
+ */
+ Connection(bool debug = false, uint32_t max_frame_size = 65535,
+ framing::ProtocolVersion=framing::highestProtocolVersion);
+ Connection(boost::shared_ptr<Connector>);
+ ~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 = "/");
+
+ /**
+ * Close the connection
+ *
+ * Any further use of this connection (without reopening it) will
+ * not succeed.
+ */
+ void close();
+
+ /**
+ * Associate a Channel with this connection and open it for use.
+ *
+ * In AMQP channels are like multi-plexed 'sessions' of work over
+ * a connection. Almost all the interaction with AMQP is done over
+ * a channel.
+ *
+ * @param connection the connection object to be associated with
+ * the channel. Call Channel::close() to close the channel.
+ */
+ void openChannel(Channel&);
+
+ /**
+ * Create a new session on this connection. Sessions allow
+ * multiple streams of work to be multiplexed over the same
+ * connection.
+ *
+ *@param detachedLifetime: A session may be detached from its
+ * channel, either by calling Session::suspend() or because of a
+ * network failure. The session state is perserved for
+ * detachedLifetime seconds to allow a call to resume(). After
+ * that the broker may discard the session state. Default is 0,
+ * meaning the session cannot be resumed.
+ */
+ Session newSession(SynchronousMode sync, uint32_t detachedLifetime=0);
+
+ /**
+ * Resume a suspendded session. A session may be resumed
+ * on a different connection to the one that created it.
+ */
+ void resume(Session& session);
+};
+
+}} // namespace qpid::client
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/client/ConnectionHandler.cpp b/qpid/cpp/src/qpid/client/ConnectionHandler.cpp
new file mode 100644
index 0000000000..e1c50c14fc
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/ConnectionHandler.cpp
@@ -0,0 +1,209 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/AMQP_HighestVersion.h"
+#include "qpid/framing/all_method_bodies.h"
+
+using namespace qpid::client;
+using namespace qpid::framing;
+using namespace boost;
+
+namespace {
+const std::string OK("OK");
+}
+
+ConnectionHandler::ConnectionHandler()
+ : StateManager(NOT_STARTED)
+{
+
+ mechanism = "PLAIN";
+ locale = "en_US";
+ heartbeat = 0;
+ maxChannels = 32767;
+ maxFrameSize = 65535;
+ insist = true;
+ version = framing::highestProtocolVersion;
+
+ ESTABLISHED.insert(FAILED);
+ ESTABLISHED.insert(OPEN);
+}
+
+void ConnectionHandler::incoming(AMQFrame& frame)
+{
+ if (getState() == CLOSED) {
+ throw Exception("Connection is closed.");
+ }
+
+ AMQBody* body = frame.getBody();
+ if (frame.getChannel() == 0) {
+ if (body->getMethod()) {
+ handle(body->getMethod());
+ } else {
+ error(503, "Cannot send content on channel zero.");
+ }
+ } else {
+ switch(getState()) {
+ case OPEN:
+ try {
+ in(frame);
+ }catch(ConnectionException& e){
+ error(e.code, e.what(), body);
+ }catch(std::exception& e){
+ error(541/*internal error*/, e.what(), body);
+ }
+ break;
+ case CLOSING:
+ QPID_LOG(warning, "Received frame on non-zero channel while closing connection; frame ignored.");
+ break;
+ default:
+ //must be in connection initialisation:
+ fail("Cannot receive frames on non-zero channel until connection is established.");
+ }
+ }
+}
+
+void ConnectionHandler::outgoing(AMQFrame& frame)
+{
+ if (getState() == OPEN) {
+ out(frame);
+ } else {
+ throw Exception("Connection is not open.");
+ }
+}
+
+void ConnectionHandler::waitForOpen()
+{
+ waitFor(ESTABLISHED);
+ if (getState() == FAILED) {
+ throw Exception("Failed to establish connection.");
+ }
+}
+
+void ConnectionHandler::close()
+{
+ switch (getState()) {
+ case NEGOTIATING:
+ case OPENING:
+ setState(FAILED);
+ break;
+ case OPEN:
+ setState(CLOSING);
+ send(ConnectionCloseBody(version, 200, OK, 0, 0));
+ waitFor(CLOSED);
+ break;
+ // Nothing to do for CLOSING, CLOSED, FAILED or NOT_STARTED
+ }
+}
+
+void ConnectionHandler::send(const framing::AMQBody& body)
+{
+ AMQFrame f(body);
+ out(f);
+}
+
+void ConnectionHandler::error(uint16_t code, const std::string& message, uint16_t classId, uint16_t methodId)
+{
+ setState(CLOSING);
+ send(ConnectionCloseBody(version, code, message, classId, methodId));
+}
+
+void ConnectionHandler::error(uint16_t code, const std::string& message, AMQBody* body)
+{
+ if (onError)
+ onError(code, message);
+ AMQMethodBody* method = body->getMethod();
+ if (method)
+ error(code, message, method->amqpClassId(), method->amqpMethodId());
+ else
+ error(code, message);
+}
+
+
+void ConnectionHandler::fail(const std::string& message)
+{
+ QPID_LOG(warning, message);
+ setState(FAILED);
+}
+
+void ConnectionHandler::handle(AMQMethodBody* method)
+{
+ switch (getState()) {
+ case NOT_STARTED:
+ if (method->isA<ConnectionStartBody>()) {
+ setState(NEGOTIATING);
+ string response = ((char)0) + uid + ((char)0) + pwd;
+ send(ConnectionStartOkBody(version, properties, mechanism, response, locale));
+ } else {
+ fail("Bad method sequence, expected connection-start.");
+ }
+ break;
+ case NEGOTIATING:
+ if (method->isA<ConnectionTuneBody>()) {
+ ConnectionTuneBody* proposal=polymorphic_downcast<ConnectionTuneBody*>(method);
+ heartbeat = proposal->getHeartbeat();
+ maxChannels = proposal->getChannelMax();
+ send(ConnectionTuneOkBody(version, maxChannels, maxFrameSize, heartbeat));
+ setState(OPENING);
+ send(ConnectionOpenBody(version, vhost, capabilities, insist));
+ //TODO: support for further security challenges
+ //} else if (method->isA<ConnectionSecureBody>()) {
+ } else {
+ fail("Unexpected method sequence, expected connection-tune.");
+ }
+ break;
+ case OPENING:
+ if (method->isA<ConnectionOpenOkBody>()) {
+ setState(OPEN);
+ //TODO: support for redirection
+ //} else if (method->isA<ConnectionRedirectBody>()) {
+ } else {
+ fail("Unexpected method sequence, expected connection-open-ok.");
+ }
+ break;
+ case OPEN:
+ if (method->isA<ConnectionCloseBody>()) {
+ send(ConnectionCloseOkBody(version));
+ setState(CLOSED);
+ ConnectionCloseBody* c=polymorphic_downcast<ConnectionCloseBody*>(method);
+ QPID_LOG(warning, "Broker closed connection: " << c->getReplyCode()
+ << ", " << c->getReplyText());
+ if (onError) {
+ onError(c->getReplyCode(), c->getReplyText());
+ }
+ } else {
+ error(503, "Unexpected method on channel zero.", method->amqpClassId(), method->amqpMethodId());
+ }
+ break;
+ case CLOSING:
+ if (method->isA<ConnectionCloseOkBody>()) {
+ if (onClose) {
+ onClose();
+ }
+ setState(CLOSED);
+ } else {
+ QPID_LOG(warning, "Received frame on channel zero while closing connection; frame ignored.");
+ }
+ break;
+ }
+}
diff --git a/qpid/cpp/src/qpid/client/ConnectionHandler.h b/qpid/cpp/src/qpid/client/ConnectionHandler.h
new file mode 100644
index 0000000000..bb50495c06
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/ConnectionHandler.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 _ConnectionHandler_
+#define _ConnectionHandler_
+
+#include "Connector.h"
+#include "StateManager.h"
+#include "ChainableFrameHandler.h"
+#include "qpid/framing/InputHandler.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/AMQMethodBody.h"
+
+namespace qpid {
+namespace client {
+
+struct ConnectionProperties
+{
+ std::string uid;
+ std::string pwd;
+ std::string vhost;
+ framing::FieldTable properties;
+ std::string mechanism;
+ std::string locale;
+ std::string capabilities;
+ uint16_t heartbeat;
+ uint16_t maxChannels;
+ uint64_t maxFrameSize;
+ bool insist;
+ framing::ProtocolVersion version;
+};
+
+class ConnectionHandler : private StateManager,
+ public ConnectionProperties,
+ public ChainableFrameHandler,
+ public framing::InputHandler
+{
+ enum STATES {NOT_STARTED, NEGOTIATING, OPENING, OPEN, CLOSING, CLOSED, FAILED};
+ std::set<int> ESTABLISHED;
+
+ void handle(framing::AMQMethodBody* method);
+ void send(const framing::AMQBody& body);
+ void error(uint16_t code, const std::string& message, uint16_t classId = 0, uint16_t methodId = 0);
+ void error(uint16_t code, const std::string& message, framing::AMQBody* body);
+
+public:
+ using InputHandler::handle;
+ typedef boost::function<void()> CloseListener;
+ typedef boost::function<void(uint16_t, const std::string&)> ErrorListener;
+
+ ConnectionHandler();
+
+ 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);
+
+ CloseListener onClose;
+ ErrorListener onError;
+};
+
+}}
+
+#endif
diff --git a/qpid/cpp/src/qpid/client/ConnectionImpl.cpp b/qpid/cpp/src/qpid/client/ConnectionImpl.cpp
new file mode 100644
index 0000000000..b248de8744
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/ConnectionImpl.cpp
@@ -0,0 +1,158 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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 "qpid/framing/constants.h"
+#include "qpid/framing/reply_exceptions.h"
+
+#include "ConnectionImpl.h"
+#include "SessionCore.h"
+
+#include <boost/bind.hpp>
+#include <boost/format.hpp>
+
+using namespace qpid::client;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+ConnectionImpl::ConnectionImpl(boost::shared_ptr<Connector> c)
+ : connector(c), isClosed(false), isClosing(false)
+{
+ handler.in = boost::bind(&ConnectionImpl::incoming, this, _1);
+ handler.out = boost::bind(&Connector::send, connector, _1);
+ handler.onClose = boost::bind(&ConnectionImpl::closed, this,
+ REPLY_SUCCESS, std::string());
+ handler.onError = boost::bind(&ConnectionImpl::closed, this, _1, _2);
+ connector->setInputHandler(&handler);
+ connector->setTimeoutHandler(this);
+ connector->setShutdownHandler(this);
+}
+
+ConnectionImpl::~ConnectionImpl() {
+ // Important to close the connector first, to ensure the
+ // connector thread does not call on us while the destructor
+ // is running.
+ connector->close();
+}
+
+void ConnectionImpl::addSession(const boost::shared_ptr<SessionCore>& session)
+{
+ Mutex::ScopedLock l(lock);
+ boost::weak_ptr<SessionCore>& s = sessions[session->getChannel()];
+ if (s.lock()) throw ChannelBusyException();
+ s = session;
+}
+
+void ConnectionImpl::handle(framing::AMQFrame& frame)
+{
+ handler.outgoing(frame);
+}
+
+void ConnectionImpl::incoming(framing::AMQFrame& frame)
+{
+ boost::shared_ptr<SessionCore> s;
+ {
+ Mutex::ScopedLock l(lock);
+ s = sessions[frame.getChannel()].lock();
+ }
+ if (!s)
+ throw ChannelErrorException(QPID_MSG("Invalid channel: " << frame.getChannel()));
+ s->in(frame);
+}
+
+void ConnectionImpl::open(const std::string& host, int port,
+ const std::string& uid, const std::string& pwd,
+ const std::string& vhost)
+{
+ //TODO: better management of connection properties
+ handler.uid = uid;
+ handler.pwd = pwd;
+ handler.vhost = vhost;
+
+ QPID_LOG(info, "Connecting to " << host << ":" << port);
+ connector->connect(host, port);
+ connector->init();
+ handler.waitForOpen();
+}
+
+void ConnectionImpl::idleIn()
+{
+ close();
+}
+
+void ConnectionImpl::idleOut()
+{
+ AMQFrame frame(in_place<AMQHeartbeatBody>());
+ connector->send(frame);
+}
+
+void ConnectionImpl::close()
+{
+ Mutex::ScopedLock l(lock);
+ if (isClosing || isClosed) return;
+ isClosing = true;
+ {
+ Mutex::ScopedUnlock u(lock);
+ handler.close();
+ }
+ closed(REPLY_SUCCESS, "Closed by client");
+}
+
+// Set closed flags and erase the sessions map, but keep the contents
+// so sessions can be updated outside the lock.
+ConnectionImpl::SessionVector ConnectionImpl::closeInternal(const Mutex::ScopedLock&) {
+ isClosed = true;
+ connector->close();
+ SessionVector save;
+ for (SessionMap::iterator i = sessions.begin(); i != sessions.end(); ++i) {
+ boost::shared_ptr<SessionCore> s = i->second.lock();
+ if (s) save.push_back(s);
+ }
+ sessions.clear();
+ return save;
+}
+
+void ConnectionImpl::closed(uint16_t code, const std::string& text)
+{
+ Mutex::ScopedLock l(lock);
+ if (isClosed) return;
+ SessionVector save(closeInternal(l));
+ Mutex::ScopedUnlock u(lock);
+ std::for_each(save.begin(), save.end(), boost::bind(&SessionCore::connectionClosed, _1, code, text));
+}
+
+static const std::string CONN_CLOSED("Connection closed by broker");
+
+void ConnectionImpl::shutdown()
+{
+ Mutex::ScopedLock l(lock);
+ if (isClosed) return;
+ SessionVector save(closeInternal(l));
+ handler.fail(CONN_CLOSED);
+ Mutex::ScopedUnlock u(lock);
+ std::for_each(save.begin(), save.end(),
+ boost::bind(&SessionCore::connectionBroke, _1, INTERNAL_ERROR, CONN_CLOSED));
+}
+
+void ConnectionImpl::erase(uint16_t ch) {
+ Mutex::ScopedLock l(lock);
+ sessions.erase(ch);
+}
+
diff --git a/qpid/cpp/src/qpid/client/ConnectionImpl.h b/qpid/cpp/src/qpid/client/ConnectionImpl.h
new file mode 100644
index 0000000000..bf8226a776
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/ConnectionImpl.h
@@ -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.
+ *
+ */
+
+#ifndef _ConnectionImpl_
+#define _ConnectionImpl_
+
+#include <map>
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+#include "qpid/framing/FrameHandler.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/ShutdownHandler.h"
+#include "qpid/sys/TimeoutHandler.h"
+#include "ConnectionHandler.h"
+#include "Connector.h"
+
+namespace qpid {
+namespace client {
+
+class SessionCore;
+
+class ConnectionImpl : public framing::FrameHandler,
+ public sys::TimeoutHandler,
+ public sys::ShutdownHandler
+
+{
+ typedef std::map<uint16_t, boost::weak_ptr<SessionCore> > SessionMap;
+ typedef std::vector<boost::shared_ptr<SessionCore> > SessionVector;
+
+ SessionMap sessions;
+ ConnectionHandler handler;
+ boost::shared_ptr<Connector> connector;
+ framing::ProtocolVersion version;
+ sys::Mutex lock;
+ bool isClosed;
+ bool isClosing;
+
+ template <class F> void detachAll(const F&);
+
+ SessionVector closeInternal(const sys::Mutex::ScopedLock&);
+ void incoming(framing::AMQFrame& frame);
+ void closed(uint16_t, const std::string&);
+ void idleOut();
+ void idleIn();
+ void shutdown();
+ bool setClosing();
+
+ public:
+ typedef boost::shared_ptr<ConnectionImpl> shared_ptr;
+
+ ConnectionImpl(boost::shared_ptr<Connector> c);
+ ~ConnectionImpl();
+
+ void addSession(const boost::shared_ptr<SessionCore>&);
+
+ void open(const std::string& host, int port = 5672,
+ const std::string& uid = "guest",
+ const std::string& pwd = "guest",
+ const std::string& virtualhost = "/");
+ void close();
+ void handle(framing::AMQFrame& frame);
+ void erase(uint16_t channel);
+ boost::shared_ptr<Connector> getConnector() { return connector; }
+};
+
+}}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/client/Connector.cpp b/qpid/cpp/src/qpid/client/Connector.cpp
new file mode 100644
index 0000000000..a0be05fbbc
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/Connector.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 <iostream>
+#include "qpid/log/Statement.h"
+#include "qpid/sys/Time.h"
+#include "qpid/framing/AMQFrame.h"
+#include "Connector.h"
+
+#include "qpid/sys/AsynchIO.h"
+#include "qpid/sys/Dispatcher.h"
+#include "qpid/sys/Poller.h"
+#include "qpid/Msg.h"
+#include <boost/bind.hpp>
+#include <boost/format.hpp>
+
+namespace qpid {
+namespace client {
+
+using namespace qpid::sys;
+using namespace qpid::framing;
+using boost::format;
+using boost::str;
+
+Connector::Connector(
+ ProtocolVersion ver, bool _debug, uint32_t buffer_size
+) : debug(_debug),
+ receive_buffer_size(buffer_size),
+ send_buffer_size(buffer_size),
+ version(ver),
+ closed(true),
+ joined(true),
+ timeout(0),
+ idleIn(0), idleOut(0),
+ timeoutHandler(0),
+ shutdownHandler(0),
+ aio(0)
+{}
+
+Connector::~Connector() {
+ close();
+}
+
+void Connector::connect(const std::string& host, int port){
+ Mutex::ScopedLock l(closedLock);
+ assert(closed);
+ socket.connect(host, port);
+ identifier=str(format("[%1% %2%]") % socket.getLocalPort() % socket.getPeerAddress());
+ closed = false;
+ poller = Poller::shared_ptr(new Poller);
+ aio = new AsynchIO(socket,
+ boost::bind(&Connector::readbuff, this, _1, _2),
+ boost::bind(&Connector::eof, this, _1),
+ boost::bind(&Connector::eof, this, _1),
+ 0, // closed
+ 0, // nobuffs
+ boost::bind(&Connector::writebuff, this, _1));
+ writer.setAio(aio);
+}
+
+void Connector::init(){
+ Mutex::ScopedLock l(closedLock);
+ assert(joined);
+ ProtocolInitiation init(version);
+ writeDataBlock(init);
+ joined = false;
+ receiver = Thread(this);
+}
+
+bool Connector::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 Connector::close() {
+ closeInternal();
+}
+
+void Connector::setInputHandler(InputHandler* handler){
+ input = handler;
+}
+
+void Connector::setShutdownHandler(ShutdownHandler* handler){
+ shutdownHandler = handler;
+}
+
+OutputHandler* Connector::getOutputHandler(){
+ return this;
+}
+
+void Connector::send(AMQFrame& frame) {
+ writer.handle(frame);
+}
+
+void Connector::handleClosed() {
+ if (closeInternal() && shutdownHandler)
+ shutdownHandler->shutdown();
+}
+
+// TODO: astitcher 20070908: This version of the code can never time out, so the idle processing
+// can never be called. The timeut processing needs to be added into the underlying Dispatcher code
+//
+// TODO: astitcher 20070908: EOF is dealt with separately now via a callback to eof
+void Connector::checkIdle(ssize_t status){
+ if(timeoutHandler){
+ AbsTime t = now();
+ if(status == Socket::SOCKET_TIMEOUT) {
+ if(idleIn && (Duration(lastIn, t) > idleIn)){
+ timeoutHandler->idleIn();
+ }
+ }
+ else if(status == 0 || status == Socket::SOCKET_EOF) {
+ handleClosed();
+ }
+ else {
+ lastIn = t;
+ }
+ if(idleOut && (Duration(lastOut, t) > idleOut)){
+ timeoutHandler->idleOut();
+ }
+ }
+}
+
+void Connector::setReadTimeout(uint16_t t){
+ idleIn = t * TIME_SEC;//t is in secs
+ if(idleIn && (!timeout || idleIn < timeout)){
+ timeout = idleIn;
+ setSocketTimeout();
+ }
+
+}
+
+void Connector::setWriteTimeout(uint16_t t){
+ idleOut = t * TIME_SEC;//t is in secs
+ if(idleOut && (!timeout || idleOut < timeout)){
+ timeout = idleOut;
+ setSocketTimeout();
+ }
+}
+
+void Connector::setSocketTimeout(){
+ socket.setTimeout(timeout);
+}
+
+void Connector::setTimeoutHandler(TimeoutHandler* handler){
+ timeoutHandler = handler;
+}
+
+struct Connector::Buff : public AsynchIO::BufferBase {
+ Buff() : AsynchIO::BufferBase(new char[65536], 65536) {}
+ ~Buff() { delete [] bytes;}
+};
+
+Connector::Writer::Writer() : aio(0), buffer(0), lastEof(0)
+{
+}
+
+Connector::Writer::~Writer() { delete buffer; }
+
+void Connector::Writer::setAio(sys::AsynchIO* a) {
+ Mutex::ScopedLock l(lock);
+ aio = a;
+ newBuffer(l);
+ identifier = str(format("[%1% %2%]") % aio->getSocket().getLocalPort() % aio->getSocket().getPeerAddress());
+}
+
+void Connector::Writer::handle(framing::AMQFrame& frame) {
+ Mutex::ScopedLock l(lock);
+ frames.push_back(frame);
+ if (frame.getEof()) {
+ lastEof = frames.size();
+ aio->notifyPendingWrite();
+ }
+ QPID_LOG(trace, "SENT " << identifier << ": " << frame);
+}
+
+void Connector::Writer::writeOne(const Mutex::ScopedLock& l) {
+ 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(l);
+}
+
+void Connector::Writer::newBuffer(const Mutex::ScopedLock&) {
+ buffer = aio->getQueuedBuffer();
+ if (!buffer) buffer = new Buff();
+ encode = framing::Buffer(buffer->bytes, buffer->byteCount);
+ framesEncoded = 0;
+}
+
+// Called in IO thread.
+void Connector::Writer::write(sys::AsynchIO&) {
+ Mutex::ScopedLock l(lock);
+ assert(buffer);
+ for (size_t i = 0; i < lastEof; ++i) {
+ AMQFrame& frame = frames[i];
+ if (frame.size() > encode.available()) writeOne(l);
+ assert(frame.size() <= encode.available());
+ frame.encode(encode);
+ ++framesEncoded;
+ }
+ frames.erase(frames.begin(), frames.begin()+lastEof);
+ lastEof = 0;
+ if (encode.getPosition() > 0) writeOne(l);
+}
+
+void Connector::readbuff(AsynchIO& aio, AsynchIO::BufferBase* buff) {
+ framing::Buffer in(buff->bytes+buff->dataStart, buff->dataCount);
+
+ 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 Connector::writebuff(AsynchIO& aio_) {
+ writer.write(aio_);
+}
+
+void Connector::writeDataBlock(const AMQDataBlock& data) {
+ AsynchIO::BufferBase* buff = new Buff;
+ framing::Buffer out(buff->bytes, buff->byteCount);
+ data.encode(out);
+ buff->dataCount = data.size();
+ aio->queueWrite(buff);
+}
+
+void Connector::eof(AsynchIO&) {
+ handleClosed();
+}
+
+// TODO: astitcher 20070908 This version of the code can never time out, so the idle processing
+// will never be called
+void Connector::run(){
+ try {
+ Dispatcher d(poller);
+
+ for (int i = 0; i < 32; i++) {
+ aio->queueReadBuffer(new Buff);
+ }
+
+ 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/qpid/cpp/src/qpid/client/Connector.h b/qpid/cpp/src/qpid/client/Connector.h
new file mode 100644
index 0000000000..ffddbfd1be
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/Connector.h
@@ -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.
+ *
+ */
+#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/Monitor.h"
+#include "qpid/sys/Socket.h"
+#include "qpid/sys/Time.h"
+#include "qpid/sys/AsynchIO.h"
+
+#include <queue>
+
+namespace qpid {
+
+namespace client {
+
+class Connector : public framing::OutputHandler,
+ private sys::Runnable
+{
+ struct Buff;
+
+ /** Batch up frames for writing to aio. */
+ class Writer : public framing::FrameHandler {
+ typedef sys::AsynchIO::BufferBase BufferBase;
+ typedef std::vector<framing::AMQFrame> Frames;
+
+ 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;
+
+ void writeOne(const sys::Mutex::ScopedLock&);
+ void newBuffer(const sys::Mutex::ScopedLock&);
+
+ public:
+
+ Writer();
+ ~Writer();
+ void setAio(sys::AsynchIO*);
+ void handle(framing::AMQFrame&);
+ void write(sys::AsynchIO&);
+ };
+
+ const bool debug;
+ const int receive_buffer_size;
+ const int send_buffer_size;
+ framing::ProtocolVersion version;
+
+ sys::Mutex closedLock;
+ bool closed;
+ bool joined;
+
+ sys::AbsTime lastIn;
+ sys::AbsTime lastOut;
+ sys::Duration timeout;
+ sys::Duration idleIn;
+ sys::Duration idleOut;
+
+ sys::TimeoutHandler* timeoutHandler;
+ sys::ShutdownHandler* shutdownHandler;
+ framing::InputHandler* input;
+ framing::InitiationHandler* initialiser;
+ framing::OutputHandler* output;
+
+ Writer writer;
+
+ sys::Thread receiver;
+
+ sys::Socket socket;
+
+ sys::AsynchIO* aio;
+ sys::Poller::shared_ptr poller;
+
+ void checkIdle(ssize_t status);
+ void setSocketTimeout();
+
+ void run();
+ void handleClosed();
+ bool closeInternal();
+
+ void readbuff(qpid::sys::AsynchIO&, qpid::sys::AsynchIO::BufferBase*);
+ void writebuff(qpid::sys::AsynchIO&);
+ void writeDataBlock(const framing::AMQDataBlock& data);
+ void eof(qpid::sys::AsynchIO&);
+
+ std::string identifier;
+
+ friend class Channel;
+
+ public:
+ Connector(framing::ProtocolVersion pVersion,
+ bool debug = false, uint32_t buffer_size = 1024);
+ virtual ~Connector();
+ virtual void connect(const std::string& host, int port);
+ virtual void init();
+ virtual void close();
+ virtual void setInputHandler(framing::InputHandler* handler);
+ virtual void setTimeoutHandler(sys::TimeoutHandler* handler);
+ virtual void setShutdownHandler(sys::ShutdownHandler* handler);
+ virtual sys::ShutdownHandler* getShutdownHandler() { return shutdownHandler; }
+ virtual framing::OutputHandler* getOutputHandler();
+ virtual void send(framing::AMQFrame& frame);
+ virtual void setReadTimeout(uint16_t timeout);
+ virtual void setWriteTimeout(uint16_t timeout);
+ const std::string& getIdentifier() const { return identifier; }
+};
+
+}}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/client/Correlator.cpp b/qpid/cpp/src/qpid/client/Correlator.cpp
new file mode 100644
index 0000000000..f30c92b992
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/Correlator.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 "Correlator.h"
+
+using qpid::client::Correlator;
+using namespace qpid::framing;
+using namespace boost;
+
+bool Correlator::receive(const AMQMethodBody* response)
+{
+ if (listeners.empty()) {
+ return false;
+ } else {
+ Listener l = listeners.front();
+ if (l) l(response);
+ listeners.pop();
+ return true;
+ }
+}
+
+void Correlator::listen(Listener l)
+{
+ listeners.push(l);
+}
+
+
diff --git a/qpid/cpp/src/qpid/client/Correlator.h b/qpid/cpp/src/qpid/client/Correlator.h
new file mode 100644
index 0000000000..45b22fb2fe
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/Correlator.h
@@ -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 <memory>
+#include <queue>
+#include <set>
+#include <boost/function.hpp>
+#include "qpid/framing/AMQMethodBody.h"
+#include "qpid/sys/Monitor.h"
+
+#ifndef _Correlator_
+#define _Correlator_
+
+namespace qpid {
+namespace client {
+
+
+class Correlator
+{
+public:
+ typedef boost::function<void(const framing::AMQMethodBody*)> Listener;
+
+ bool receive(const framing::AMQMethodBody*);
+ void listen(Listener l);
+
+private:
+ std::queue<Listener> listeners;
+};
+
+}
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/client/Demux.cpp b/qpid/cpp/src/qpid/client/Demux.cpp
new file mode 100644
index 0000000000..cb9372cee7
--- /dev/null
+++ b/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(); }
+
+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()
+{
+ sys::Mutex::ScopedLock l(lock);
+ for (iterator i = records.begin(); i != records.end(); i++) {
+ i->queue->close();
+ }
+ defaultQueue->close();
+}
+
+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/qpid/cpp/src/qpid/client/Demux.h b/qpid/cpp/src/qpid/client/Demux.h
new file mode 100644
index 0000000000..dce24223f2
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/Demux.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 <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 {
+
+class ByTransferDest
+{
+ const std::string dest;
+public:
+ ByTransferDest(const std::string& dest);
+ bool operator()(const framing::FrameSet& frameset) const;
+};
+
+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();
+ 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/qpid/cpp/src/qpid/client/Dispatcher.cpp b/qpid/cpp/src/qpid/client/Dispatcher.cpp
new file mode 100644
index 0000000000..2484dabf1f
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/Dispatcher.cpp
@@ -0,0 +1,142 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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 "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 {
+
+Subscriber::Subscriber(Session& s, MessageListener* l, AckPolicy a) : session(s), listener(l), autoAck(a) {}
+
+void Subscriber::received(Message& msg)
+{
+ if (listener) {
+ listener->received(msg);
+ autoAck.ack(msg);
+ }
+}
+
+Dispatcher::Dispatcher(Session& s, const std::string& q)
+ : session(s), running(false), autoStop(true)
+{
+ queue = q.empty() ?
+ session.getExecution().getDemux().getDefault() :
+ session.getExecution().getDemux().get(q);
+}
+
+void Dispatcher::start()
+{
+ worker = Thread(this);
+}
+
+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, session);
+ Subscriber::shared_ptr 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(error, "No handler found for " << *(content->getMethod()));
+ }
+ }
+ }
+ } catch (const ClosedException&) {
+ //ignore it and return
+ }
+}
+
+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;
+}
+
+Subscriber::shared_ptr 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(
+ MessageListener* listener, AckPolicy autoAck
+)
+{
+ ScopedLock<Mutex> l(lock);
+ defaultListener = Subscriber::shared_ptr(
+ new Subscriber(session, listener, autoAck));
+}
+
+void Dispatcher::listen(const std::string& destination, MessageListener* listener, AckPolicy autoAck)
+{
+ ScopedLock<Mutex> l(lock);
+ listeners[destination] = Subscriber::shared_ptr(
+ new Subscriber(session, listener, autoAck));
+}
+
+void Dispatcher::cancel(const std::string& destination)
+{
+ ScopedLock<Mutex> l(lock);
+ listeners.erase(destination);
+ if (autoStop && listeners.empty())
+ queue->close();
+}
+
+}}
diff --git a/qpid/cpp/src/qpid/client/Dispatcher.h b/qpid/cpp/src/qpid/client/Dispatcher.h
new file mode 100644
index 0000000000..e23d0c198c
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/Dispatcher.h
@@ -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.
+ *
+ */
+#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 "AckPolicy.h"
+
+namespace qpid {
+namespace client {
+
+class Subscriber : public MessageListener
+{
+ Session& session;
+ MessageListener* const listener;
+ AckPolicy autoAck;
+
+public:
+ typedef boost::shared_ptr<Subscriber> shared_ptr;
+ Subscriber(Session& session, MessageListener* listener, AckPolicy);
+ void received(Message& msg);
+
+};
+
+typedef framing::Handler<framing::FrameSet> FrameSetHandler;
+
+class Dispatcher : public sys::Runnable
+{
+ typedef std::map<std::string, Subscriber::shared_ptr> Listeners;
+ sys::Mutex lock;
+ sys::Thread worker;
+ Session& session;
+ Demux::QueuePtr queue;
+ bool running;
+ bool autoStop;
+ Listeners listeners;
+ Subscriber::shared_ptr defaultListener;
+ std::auto_ptr<FrameSetHandler> handler;
+
+ Subscriber::shared_ptr find(const std::string& name);
+ bool isStopped();
+
+public:
+ Dispatcher(Session& session, const std::string& queue = "");
+
+ void start();
+ void run();
+ void stop();
+ void setAutoStop(bool b);
+
+ void listen(MessageListener* listener, AckPolicy autoAck=AckPolicy());
+ void listen(const std::string& destination, MessageListener* listener, AckPolicy autoAck=AckPolicy());
+ void cancel(const std::string& destination);
+};
+
+}}
+
+#endif
diff --git a/qpid/cpp/src/qpid/client/Exchange.cpp b/qpid/cpp/src/qpid/client/Exchange.cpp
new file mode 100644
index 0000000000..e7fbdeb47e
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/Exchange.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 "Exchange.h"
+
+qpid::client::Exchange::Exchange(std::string _name, std::string _type) : name(_name), type(_type){}
+const std::string& qpid::client::Exchange::getName() const { return name; }
+const std::string& qpid::client::Exchange::getType() const { return type; }
+
+const std::string qpid::client::Exchange::DIRECT_EXCHANGE = "direct";
+const std::string qpid::client::Exchange::TOPIC_EXCHANGE = "topic";
+const std::string qpid::client::Exchange::HEADERS_EXCHANGE = "headers";
+
+const qpid::client::Exchange qpid::client::Exchange::DEFAULT_EXCHANGE("", DIRECT_EXCHANGE);
+const qpid::client::Exchange qpid::client::Exchange::STANDARD_DIRECT_EXCHANGE("amq.direct", DIRECT_EXCHANGE);
+const qpid::client::Exchange qpid::client::Exchange::STANDARD_TOPIC_EXCHANGE("amq.topic", TOPIC_EXCHANGE);
+const qpid::client::Exchange qpid::client::Exchange::STANDARD_HEADERS_EXCHANGE("amq.headers", HEADERS_EXCHANGE);
diff --git a/qpid/cpp/src/qpid/client/Exchange.h b/qpid/cpp/src/qpid/client/Exchange.h
new file mode 100644
index 0000000000..0640e4fe2c
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/Exchange.h
@@ -0,0 +1,106 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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 _Exchange_
+#define _Exchange_
+
+namespace qpid {
+namespace client {
+
+ /**
+ * DEPRECATED
+ *
+ * A 'handle' used to represent an AMQP exchange in the Channel
+ * methods. Exchanges are the destinations to which messages are
+ * published.
+ *
+ * There are different types of exchange (the standard types are
+ * available as static constants, see DIRECT_EXCHANGE,
+ * TOPIC_EXCHANGE and HEADERS_EXCHANGE). A Queue can be bound to
+ * an exchange using Channel::bind() and messages published to
+ * that exchange are then routed to the queue based on the details
+ * of the binding and the type of exchange.
+ *
+ * There are some standard exchange instances that are predeclared
+ * on all AMQP brokers. These are defined as static members
+ * STANDARD_DIRECT_EXCHANGE, STANDARD_TOPIC_EXCHANGE and
+ * STANDARD_HEADERS_EXCHANGE. There is also the 'default' exchange
+ * (member DEFAULT_EXCHANGE) which is nameless and of type
+ * 'direct' and has every declared queue bound to it by queue
+ * name.
+ */
+ class Exchange{
+ const std::string name;
+ const std::string type;
+
+ public:
+ /**
+ * A direct exchange routes messages published with routing
+ * key X to any queue bound with key X (i.e. an exact match is
+ * used).
+ */
+ static const std::string DIRECT_EXCHANGE;
+ /**
+ * A topic exchange treat the key with which a queue is bound
+ * as a pattern and routes all messages whose routing keys
+ * match that pattern to the bound queue. The routing key for
+ * a message must consist of zero or more alpha-numeric words
+ * delimited by dots. The pattern is of a similar form but *
+ * can be used to match excatly one word and # can be used to
+ * match zero or more words.
+ */
+ static const std::string TOPIC_EXCHANGE;
+ /**
+ * The headers exchange routes messages based on whether their
+ * headers match the binding arguments specified when
+ * binding. (see the AMQP spec for more details).
+ */
+ static const std::string HEADERS_EXCHANGE;
+
+ /**
+ * The 'default' exchange, nameless and of type 'direct'. Has
+ * every declared queue bound to it by name.
+ */
+ static const Exchange DEFAULT_EXCHANGE;
+ /**
+ * The standard direct exchange, named amq.direct.
+ */
+ static const Exchange STANDARD_DIRECT_EXCHANGE;
+ /**
+ * The standard topic exchange, named amq.topic.
+ */
+ static const Exchange STANDARD_TOPIC_EXCHANGE;
+ /**
+ * The standard headers exchange, named amq.header.
+ */
+ static const Exchange STANDARD_HEADERS_EXCHANGE;
+
+ Exchange(std::string name, std::string type = DIRECT_EXCHANGE);
+ const std::string& getName() const;
+ const std::string& getType() const;
+ };
+
+}
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/client/Execution.h b/qpid/cpp/src/qpid/client/Execution.h
new file mode 100644
index 0000000000..5f717de586
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/Execution.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 _Execution_
+#define _Execution_
+
+#include "qpid/framing/SequenceNumber.h"
+#include "Demux.h"
+
+namespace qpid {
+namespace client {
+
+/**
+ * Provides more detailed access to the amqp 'execution layer'.
+ */
+class Execution
+{
+public:
+ virtual ~Execution() {}
+ virtual void sendSyncRequest() = 0;
+ virtual void sendFlushRequest() = 0;
+ virtual void completed(const framing::SequenceNumber& id, bool cumulative, bool send) = 0;
+ virtual Demux& getDemux() = 0;
+ virtual bool isComplete(const framing::SequenceNumber& id) = 0;
+ virtual bool isCompleteUpTo(const framing::SequenceNumber& id) = 0;
+ virtual void setCompletionListener(boost::function<void()>) = 0;
+ virtual void syncWait(const framing::SequenceNumber& id) = 0;
+ virtual framing::SequenceNumber lastSent() const = 0;
+};
+
+}}
+
+#endif
diff --git a/qpid/cpp/src/qpid/client/ExecutionHandler.cpp b/qpid/cpp/src/qpid/client/ExecutionHandler.cpp
new file mode 100644
index 0000000000..afdd13c9e9
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/ExecutionHandler.cpp
@@ -0,0 +1,267 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "ExecutionHandler.h"
+#include "qpid/Exception.h"
+#include "qpid/framing/BasicDeliverBody.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/framing/AMQP_HighestVersion.h"
+#include "qpid/framing/all_method_bodies.h"
+#include "qpid/framing/ServerInvoker.h"
+#include "qpid/client/FutureCompletion.h"
+#include <boost/bind.hpp>
+
+using namespace qpid::client;
+using namespace qpid::framing;
+using namespace boost;
+using qpid::sys::Mutex;
+
+bool isMessageMethod(AMQMethodBody* method)
+{
+ return method->isA<BasicDeliverBody>() || method->isA<MessageTransferBody>() || method->isA<BasicGetOkBody>();
+}
+
+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);
+}
+
+ExecutionHandler::ExecutionHandler(uint64_t _maxFrameSize) :
+ version(framing::highestProtocolVersion), maxFrameSize(_maxFrameSize) {}
+
+//incoming:
+void ExecutionHandler::handle(AMQFrame& frame)
+{
+ if (!invoke(*this, *frame.getBody())) {
+ if (!arriving) {
+ arriving = FrameSet::shared_ptr(new FrameSet(++incomingCounter));
+ }
+ arriving->append(frame);
+ if (arriving->isComplete()) {
+ if (arriving->isContentBearing() || !correlation.receive(arriving->getMethod())) {
+ demux.handle(arriving);
+ }
+ arriving.reset();
+ }
+ }
+}
+
+void ExecutionHandler::complete(uint32_t cumulative, const SequenceNumberSet& range)
+{
+ if (range.size() % 2) { //must be even number
+ throw NotAllowedException(QPID_MSG("Received odd number of elements in ranged mark"));
+ } else {
+ SequenceNumber mark(cumulative);
+ {
+ Mutex::ScopedLock l(lock);
+ outgoingCompletionStatus.update(mark, range);
+ }
+ if (completionListener) completionListener();
+ completion.completed(outgoingCompletionStatus.mark);
+ //TODO: signal listeners of early notification?
+ }
+}
+
+void ExecutionHandler::flush()
+{
+ sendCompletion();
+}
+
+void ExecutionHandler::noop()
+{
+ //do nothing
+}
+
+void ExecutionHandler::result(uint32_t command, const std::string& data)
+{
+ completion.received(command, data);
+}
+
+void ExecutionHandler::sync()
+{
+ //TODO: implement - need to note the mark requested and then
+ //remember to send a response when that point is reached
+}
+
+void ExecutionHandler::flushTo(const framing::SequenceNumber& point)
+{
+ Mutex::ScopedLock l(lock);
+ if (point > outgoingCompletionStatus.mark) {
+ sendFlushRequest();
+ }
+}
+
+void ExecutionHandler::sendFlushRequest()
+{
+ Mutex::ScopedLock l(lock);
+ AMQFrame frame(in_place<ExecutionFlushBody>());
+ out(frame);
+}
+
+void ExecutionHandler::syncTo(const framing::SequenceNumber& point)
+{
+ Mutex::ScopedLock l(lock);
+ if (point > outgoingCompletionStatus.mark) {
+ sendSyncRequest();
+ }
+}
+
+
+void ExecutionHandler::sendSyncRequest()
+{
+ Mutex::ScopedLock l(lock);
+ AMQFrame frame(in_place<ExecutionSyncBody>());
+ out(frame);
+}
+
+void ExecutionHandler::completed(const SequenceNumber& id, bool cumulative, bool send)
+{
+ {
+ Mutex::ScopedLock l(lock);
+ if (id > incomingCompletionStatus.mark) {
+ if (cumulative) {
+ incomingCompletionStatus.update(incomingCompletionStatus.mark, id);
+ } else {
+ incomingCompletionStatus.update(id, id);
+ }
+ }
+ }
+ if (send) {
+ sendCompletion();
+ }
+}
+
+
+void ExecutionHandler::sendCompletion()
+{
+ Mutex::ScopedLock l(lock);
+ SequenceNumberSet range;
+ incomingCompletionStatus.collectRanges(range);
+ AMQFrame frame(
+ in_place<ExecutionCompleteBody>(
+ version, incomingCompletionStatus.mark.getValue(), range));
+ out(frame);
+}
+
+SequenceNumber ExecutionHandler::lastSent() const { return outgoingCounter; }
+
+SequenceNumber ExecutionHandler::send(const AMQBody& command, CompletionTracker::ResultListener listener)
+{
+ Mutex::ScopedLock l(lock);
+ return send(command, listener, false);
+}
+
+SequenceNumber ExecutionHandler::send(const AMQBody& command, CompletionTracker::ResultListener l, bool hasContent)
+{
+ SequenceNumber id = ++outgoingCounter;
+ if(l) {
+ completion.listenForResult(id, l);
+ }
+ AMQFrame frame(command);
+ if (hasContent) {
+ frame.setEof(false);
+ }
+ out(frame);
+ return id;
+}
+
+SequenceNumber ExecutionHandler::send(const AMQBody& command, const MethodContent& content,
+ CompletionTracker::ResultListener listener)
+{
+ Mutex::ScopedLock l(lock);
+ SequenceNumber id = send(command, listener, true);
+ sendContent(content);
+ return id;
+}
+
+void ExecutionHandler::sendContent(const MethodContent& content)
+{
+ AMQFrame header(content.getHeader());
+ header.setBof(false);
+ u_int64_t data_length = content.getData().length();
+ if(data_length > 0){
+ header.setEof(false);
+ out(header);
+ const u_int32_t frag_size = maxFrameSize - (AMQFrame::frameOverhead() - 1 /*end of frame marker included in overhead but not in size*/);
+ if(data_length < frag_size){
+ AMQFrame frame(in_place<AMQContentBody>(content.getData()));
+ frame.setBof(false);
+ out(frame);
+ }else{
+ u_int32_t offset = 0;
+ u_int32_t remaining = data_length - offset;
+ while (remaining > 0) {
+ u_int32_t length = remaining > frag_size ? frag_size : remaining;
+ string frag(content.getData().substr(offset, length));
+ AMQFrame frame(in_place<AMQContentBody>(frag));
+ frame.setBof(false);
+ if (offset > 0) {
+ frame.setBos(false);
+ }
+ offset += length;
+ remaining = data_length - offset;
+ if (remaining) {
+ frame.setEos(false);
+ frame.setEof(false);
+ }
+ out(frame);
+ }
+ }
+ } else {
+ out(header);
+ }
+}
+
+bool ExecutionHandler::isComplete(const SequenceNumber& id)
+{
+ Mutex::ScopedLock l(lock);
+ return outgoingCompletionStatus.covers(id);
+}
+
+bool ExecutionHandler::isCompleteUpTo(const SequenceNumber& id)
+{
+ Mutex::ScopedLock l(lock);
+ return outgoingCompletionStatus.mark >= id;
+}
+
+void ExecutionHandler::setCompletionListener(boost::function<void()> l)
+{
+ completionListener = l;
+}
+
+
+void ExecutionHandler::syncWait(const SequenceNumber& id) {
+ syncTo(id);
+ FutureCompletion fc;
+ completion.listenForCompletion(
+ id, boost::bind(&FutureCompletion::completed, &fc)
+ );
+ fc.waitForCompletion();
+ assert(isCompleteUpTo(id));
+}
diff --git a/qpid/cpp/src/qpid/client/ExecutionHandler.h b/qpid/cpp/src/qpid/client/ExecutionHandler.h
new file mode 100644
index 0000000000..d9113b683b
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/ExecutionHandler.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.
+ *
+ */
+#ifndef _ExecutionHandler_
+#define _ExecutionHandler_
+
+#include <queue>
+#include "qpid/framing/AccumulatedAck.h"
+#include "qpid/framing/AMQP_ServerOperations.h"
+#include "qpid/framing/FrameSet.h"
+#include "qpid/framing/MethodContent.h"
+#include "qpid/framing/SequenceNumber.h"
+#include "qpid/sys/Mutex.h"
+#include "ChainableFrameHandler.h"
+#include "CompletionTracker.h"
+#include "Correlator.h"
+#include "Demux.h"
+#include "Execution.h"
+
+namespace qpid {
+namespace client {
+
+class ExecutionHandler :
+ public framing::AMQP_ServerOperations::ExecutionHandler,
+ public framing::FrameHandler,
+ public Execution
+{
+ framing::SequenceNumber incomingCounter;
+ framing::AccumulatedAck incomingCompletionStatus;
+ framing::SequenceNumber outgoingCounter;
+ framing::AccumulatedAck outgoingCompletionStatus;
+ framing::FrameSet::shared_ptr arriving;
+ Correlator correlation;
+ CompletionTracker completion;
+ Demux demux;
+ sys::Mutex lock;
+ framing::ProtocolVersion version;
+ uint64_t maxFrameSize;
+ boost::function<void()> completionListener;
+
+ void complete(uint32_t mark, const framing::SequenceNumberSet& range);
+ void flush();
+ void noop();
+ void result(uint32_t command, const std::string& data);
+ void sync();
+
+ void sendCompletion();
+
+ framing::SequenceNumber send(const framing::AMQBody&, CompletionTracker::ResultListener, bool hasContent);
+ void sendContent(const framing::MethodContent&);
+
+public:
+ typedef CompletionTracker::ResultListener ResultListener;
+
+ // Allow other classes to set the out handler.
+ framing::FrameHandler::Chain out;
+
+ ExecutionHandler(uint64_t maxFrameSize = 65535);
+
+ // Incoming handler.
+ void handle(framing::AMQFrame& frame);
+
+ framing::SequenceNumber send(const framing::AMQBody& command, ResultListener=ResultListener());
+ framing::SequenceNumber send(const framing::AMQBody& command, const framing::MethodContent& content,
+ ResultListener=ResultListener());
+ framing::SequenceNumber lastSent() const;
+ void sendSyncRequest();
+ void sendFlushRequest();
+ void completed(const framing::SequenceNumber& id, bool cumulative, bool send);
+ void syncTo(const framing::SequenceNumber& point);
+ void flushTo(const framing::SequenceNumber& point);
+ void syncWait(const framing::SequenceNumber& id);
+
+ bool isComplete(const framing::SequenceNumber& id);
+ bool isCompleteUpTo(const framing::SequenceNumber& id);
+
+ void setMaxFrameSize(uint64_t size) { maxFrameSize = size; }
+ Correlator& getCorrelator() { return correlation; }
+ CompletionTracker& getCompletionTracker() { return completion; }
+ Demux& getDemux() { return demux; }
+
+ void setCompletionListener(boost::function<void()>);
+};
+
+}}
+
+#endif
diff --git a/qpid/cpp/src/qpid/client/Future.h b/qpid/cpp/src/qpid/client/Future.h
new file mode 100644
index 0000000000..d07f9f149c
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/Future.h
@@ -0,0 +1,108 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 "FutureResponse.h"
+#include "FutureResult.h"
+#include "SessionCore.h"
+
+namespace qpid {
+namespace client {
+
+class Future : private framing::StructHelper
+{
+ framing::SequenceNumber command;
+ boost::shared_ptr<FutureResponse> response;
+ boost::shared_ptr<FutureResult> result;
+ bool complete;
+
+public:
+ Future() : complete(false) {}
+ Future(const framing::SequenceNumber& id) : command(id), complete(false) {}
+
+ void sync(SessionCore& session)
+ {
+ if (!isComplete(session)) {
+ session.getExecution().syncTo(command);
+ wait(session);
+ }
+ }
+
+ void wait(SessionCore& session)
+ {
+ if (!isComplete(session)) {
+ FutureCompletion callback;
+ session.getExecution().getCompletionTracker().listenForCompletion(
+ command,
+ boost::bind(&FutureCompletion::completed, &callback)
+ );
+ callback.waitForCompletion();
+ session.assertOpen();
+ complete = true;
+ }
+ }
+
+ framing::AMQMethodBody* getResponse(SessionCore& session)
+ {
+ if (response) {
+ session.getExecution().getCompletionTracker().listenForCompletion(
+ command,
+ boost::bind(&FutureResponse::completed, response)
+ );
+ return response->getResponse(session);
+ } else {
+ throw Exception("Response not expected");
+ }
+ }
+
+ template <class T> void decodeResult(T& value, SessionCore& session)
+ {
+ if (result) {
+ decode(value, result->getResult(session));
+ } else {
+ throw Exception("Result not expected");
+ }
+ }
+
+ bool isComplete(SessionCore& session) {
+ return complete || session.getExecution().isComplete(command);
+ }
+
+ bool isCompleteUpTo(SessionCore& session) {
+ return complete || session.getExecution().isCompleteUpTo(command);
+ }
+
+ void setCommandId(const framing::SequenceNumber& id) { command = id; }
+ void setFutureResponse(boost::shared_ptr<FutureResponse> r) { response = r; }
+ void setFutureResult(boost::shared_ptr<FutureResult> r) { result = r; }
+};
+
+}}
+
+#endif
diff --git a/qpid/cpp/src/qpid/client/FutureCompletion.cpp b/qpid/cpp/src/qpid/client/FutureCompletion.cpp
new file mode 100644
index 0000000000..130c65d6aa
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/client/FutureCompletion.h b/qpid/cpp/src/qpid/client/FutureCompletion.h
new file mode 100644
index 0000000000..1897230230
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/FutureCompletion.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 _FutureCompletion_
+#define _FutureCompletion_
+
+#include "qpid/framing/amqp_framing.h"
+#include "qpid/sys/Monitor.h"
+
+namespace qpid {
+namespace client {
+
+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/qpid/cpp/src/qpid/client/FutureFactory.cpp b/qpid/cpp/src/qpid/client/FutureFactory.cpp
new file mode 100644
index 0000000000..7f9d51e77f
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/FutureFactory.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 "FutureFactory.h"
+
+using namespace qpid::client;
+using namespace boost;
+
+shared_ptr<FutureCompletion> FutureFactory::createCompletion()
+{
+ shared_ptr<FutureCompletion> f(new FutureCompletion());
+ weak_ptr<FutureCompletion> w(f);
+ set.push_back(w);
+ return f;
+}
+
+shared_ptr<FutureResponse> FutureFactory::createResponse()
+{
+ shared_ptr<FutureResponse> f(new FutureResponse());
+ weak_ptr<FutureCompletion> w(static_pointer_cast<FutureCompletion>(f));
+ set.push_back(w);
+ return f;
+}
+
+void FutureFactory::close(uint16_t code, const std::string& text)
+{
+ for (WeakPtrSet::iterator i = set.begin(); i != set.end(); i++) {
+ shared_ptr<FutureCompletion> p = i->lock();
+ if (p) {
+ p->close(code, text);
+ }
+ }
+}
diff --git a/qpid/cpp/src/qpid/client/FutureFactory.h b/qpid/cpp/src/qpid/client/FutureFactory.h
new file mode 100644
index 0000000000..b126e296fd
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/FutureFactory.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 _FutureFactory_
+#define _FutureFactory_
+
+#include <vector>
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+#include "FutureCompletion.h"
+#include "FutureResponse.h"
+
+namespace qpid {
+namespace client {
+
+class FutureFactory
+{
+ typedef std::vector< boost::weak_ptr<FutureCompletion> > WeakPtrSet;
+ WeakPtrSet set;
+
+public:
+ boost::shared_ptr<FutureCompletion> createCompletion();
+ boost::shared_ptr<FutureResponse> createResponse();
+ void close(uint16_t code, const std::string& text);
+};
+
+}}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/client/FutureResponse.cpp b/qpid/cpp/src/qpid/client/FutureResponse.cpp
new file mode 100644
index 0000000000..32d99531fa
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/FutureResponse.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 "FutureResponse.h"
+
+#include "SessionCore.h"
+
+using namespace qpid::client;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+
+AMQMethodBody* FutureResponse::getResponse(SessionCore& session)
+{
+ waitForCompletion();
+ session.assertOpen();
+ return response.getMethod();
+}
+
+void FutureResponse::received(const AMQMethodBody* r)
+{
+ Monitor::ScopedLock l(lock);
+ response.setBody(*r);
+ complete = true;
+ lock.notifyAll();
+}
+
diff --git a/qpid/cpp/src/qpid/client/FutureResponse.h b/qpid/cpp/src/qpid/client/FutureResponse.h
new file mode 100644
index 0000000000..534ca01bb7
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/FutureResponse.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 _FutureResponse_
+#define _FutureResponse_
+
+#include "qpid/framing/amqp_framing.h"
+#include "qpid/framing/BodyHolder.h"
+#include "FutureCompletion.h"
+
+namespace qpid {
+namespace client {
+
+class SessionCore;
+
+class FutureResponse : public FutureCompletion
+{
+ framing::BodyHolder response;
+public:
+ framing::AMQMethodBody* getResponse(SessionCore& session);
+ void received(const framing::AMQMethodBody* response);
+};
+
+}}
+
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/client/FutureResult.cpp b/qpid/cpp/src/qpid/client/FutureResult.cpp
new file mode 100644
index 0000000000..681202edea
--- /dev/null
+++ b/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 "SessionCore.h"
+
+using namespace qpid::client;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+const std::string& FutureResult::getResult(SessionCore& 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/qpid/cpp/src/qpid/client/FutureResult.h b/qpid/cpp/src/qpid/client/FutureResult.h
new file mode 100644
index 0000000000..3117b63802
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/FutureResult.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 _FutureResult_
+#define _FutureResult_
+
+#include <string>
+#include "qpid/framing/amqp_framing.h"
+#include "FutureCompletion.h"
+
+namespace qpid {
+namespace client {
+
+class SessionCore;
+
+class FutureResult : public FutureCompletion
+{
+ std::string result;
+public:
+ const std::string& getResult(SessionCore& session) const;
+ void received(const std::string& result);
+};
+
+}}
+
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/client/LocalQueue.cpp b/qpid/cpp/src/qpid/client/LocalQueue.cpp
new file mode 100644
index 0000000000..951996f005
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/LocalQueue.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 "LocalQueue.h"
+#include "qpid/Exception.h"
+#include "qpid/framing/FrameSet.h"
+#include "qpid/framing/reply_exceptions.h"
+
+namespace qpid {
+namespace client {
+
+using namespace framing;
+
+LocalQueue::LocalQueue(AckPolicy a) : autoAck(a) {}
+LocalQueue::~LocalQueue() {}
+
+Message LocalQueue::pop() {
+ if (!queue)
+ throw ClosedException();
+ FrameSet::shared_ptr content = queue->pop();
+ if (content->isA<MessageTransferBody>()) {
+ Message m(*content, session);
+ autoAck.ack(m);
+ return m;
+ }
+ else
+ throw CommandInvalidException(
+ QPID_MSG("Unexpected method: " << content->getMethod()));
+}
+
+void LocalQueue::setAckPolicy(AckPolicy a) { autoAck=a; }
+
+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/qpid/cpp/src/qpid/client/LocalQueue.h b/qpid/cpp/src/qpid/client/LocalQueue.h
new file mode 100644
index 0000000000..f8b2c2e0b3
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/LocalQueue.h
@@ -0,0 +1,60 @@
+#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/Demux.h"
+#include "qpid/client/AckPolicy.h"
+
+namespace qpid {
+namespace client {
+
+/**
+ * Local representation of a remote queue.
+ *
+ * \ingroup clientapi
+ */
+class LocalQueue
+{
+ public:
+ LocalQueue(AckPolicy=AckPolicy());
+ ~LocalQueue();
+
+ /** Pop the next message off the queue.
+ *@exception ClosedException if subscription has been closed.
+ */
+ Message pop();
+ bool empty() const;
+ size_t size() const;
+ void setAckPolicy(AckPolicy);
+
+ private:
+ friend class SubscriptionManager;
+ Session session;
+ Demux::QueuePtr queue;
+ AckPolicy autoAck;
+};
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_LOCALQUEUE_H*/
diff --git a/qpid/cpp/src/qpid/client/Message.h b/qpid/cpp/src/qpid/client/Message.h
new file mode 100644
index 0000000000..daac30ba36
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/Message.h
@@ -0,0 +1,104 @@
+#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 representation of messages for sent or recived through the
+ * client api.
+ *
+ * \ingroup clientapi
+ */
+class Message : public framing::TransferContent
+{
+public:
+ Message(const std::string& data_=std::string(),
+ const std::string& routingKey=std::string(),
+ const std::string& exchange=std::string()
+ ) : TransferContent(data_, routingKey, exchange) {}
+
+ std::string getDestination() const
+ {
+ return method.getDestination();
+ }
+
+ bool isRedelivered() const
+ {
+ return hasDeliveryProperties() && getDeliveryProperties().getRedelivered();
+ }
+
+ void setRedelivered(bool redelivered)
+ {
+ getDeliveryProperties().setRedelivered(redelivered);
+ }
+
+ framing::FieldTable& getHeaders()
+ {
+ return getMessageProperties().getApplicationHeaders();
+ }
+
+ void acknowledge(Session& session, bool cumulative = true, bool send = true) const
+ {
+ session.getExecution().completed(id, cumulative, send);
+ }
+
+ void acknowledge(bool cumulative = true, bool send = true) const
+ {
+ const_cast<Session&>(session).getExecution().completed(id, cumulative, send);
+ }
+
+ /**@internal for incoming messages */
+ Message(const framing::FrameSet& frameset, Session s) :
+ method(*frameset.as<framing::MessageTransferBody>()), id(frameset.getId()), session(s)
+ {
+ populate(frameset);
+ }
+
+ const framing::MessageTransferBody& getMethod() const
+ {
+ return method;
+ }
+
+ const framing::SequenceNumber& getId() const
+ {
+ return id;
+ }
+
+ /**@internal use for incoming messages. */
+ void setSession(Session s) { session=s; }
+private:
+ //method and id are only set for received messages:
+ framing::MessageTransferBody method;
+ framing::SequenceNumber id;
+ Session session;
+};
+
+}}
+
+#endif /*!_client_Message_h*/
diff --git a/qpid/cpp/src/qpid/client/MessageListener.cpp b/qpid/cpp/src/qpid/client/MessageListener.cpp
new file mode 100644
index 0000000000..68ebedeb0d
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/client/MessageListener.h b/qpid/cpp/src/qpid/client/MessageListener.h
new file mode 100644
index 0000000000..86e5dd63dc
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/MessageListener.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.
+ *
+ */
+#include <string>
+
+#ifndef _MessageListener_
+#define _MessageListener_
+
+#include "Message.h"
+
+namespace qpid {
+namespace client {
+
+ /**
+ * An interface through which asynchronously delivered messages
+ * can be received by an application.
+ *
+ * @see Channel::consume()
+ *
+ * \ingroup clientapi
+ */
+ class MessageListener{
+ public:
+ virtual ~MessageListener();
+ virtual void received(Message& msg) = 0;
+ };
+
+}
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/client/MessageQueue.h b/qpid/cpp/src/qpid/client/MessageQueue.h
new file mode 100644
index 0000000000..e9b7a9fe58
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/MessageQueue.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 _MessageQueue_
+#define _MessageQueue_
+#include <iostream>
+#include "qpid/sys/BlockingQueue.h"
+#include "MessageListener.h"
+
+namespace qpid {
+namespace client {
+
+/**
+ * A MessageListener implementation that simply queues up
+ * messages.
+ *
+ * \ingroup clientapi
+ */
+class MessageQueue : public sys::BlockingQueue<Message>, public MessageListener
+{
+ public:
+ void received(Message& msg)
+ {
+ push(msg);
+ }
+};
+
+}
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/client/Queue.cpp b/qpid/cpp/src/qpid/client/Queue.cpp
new file mode 100644
index 0000000000..1752a48a3a
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/Queue.cpp
@@ -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 "Queue.h"
+
+qpid::client::Queue::Queue() : name(""), autodelete(true), exclusive(true), durable(false){}
+
+qpid::client::Queue::Queue(std::string _name) : name(_name), autodelete(false), exclusive(false), durable(false){}
+
+qpid::client::Queue::Queue(std::string _name, bool temp) : name(_name), autodelete(temp), exclusive(temp), durable(false){}
+
+qpid::client::Queue::Queue(std::string _name, bool _autodelete, bool _exclusive, bool _durable)
+ : name(_name), autodelete(_autodelete), exclusive(_exclusive), durable(_durable){}
+
+const std::string& qpid::client::Queue::getName() const{
+ return name;
+}
+
+void qpid::client::Queue::setName(const std::string& _name){
+ name = _name;
+}
+
+bool qpid::client::Queue::isAutoDelete() const{
+ return autodelete;
+}
+
+bool qpid::client::Queue::isExclusive() const{
+ return exclusive;
+}
+
+bool qpid::client::Queue::isDurable() const{
+ return durable;
+}
+
+void qpid::client::Queue::setDurable(bool _durable){
+ durable = _durable;
+}
+
+
+
+
diff --git a/qpid/cpp/src/qpid/client/Queue.h b/qpid/cpp/src/qpid/client/Queue.h
new file mode 100644
index 0000000000..078e04c29e
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/Queue.h
@@ -0,0 +1,103 @@
+#ifndef _client_Queue_h
+#define _client_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 <string>
+
+namespace qpid {
+namespace client {
+
+ /**
+ * DEPRECATED
+ *
+ * A 'handle' used to represent an AMQP queue in the Channel
+ * methods. Creating an instance of this class does not cause the
+ * queue to be created on the broker. Rather, an instance of this
+ * class should be passed to Channel::declareQueue() to ensure
+ * that the queue exists or is created.
+ *
+ * Queues hold messages and allow clients to consume
+ * (see Channel::consume()) or get (see Channel::get()) those messags. A
+ * queue receives messages by being bound to one or more Exchange;
+ * messages published to that exchange may then be routed to the
+ * queue based on the details of the binding and the type of the
+ * exchange (see Channel::bind()).
+ *
+ * Queues are identified by a name. They can be exclusive (in which
+ * case they can only be used in the context of the connection
+ * over which they were declared, and are deleted when then
+ * connection closes), or they can be shared. Shared queues can be
+ * auto deleted when they have no consumers.
+ *
+ * We use the term 'temporary queue' to refer to an exclusive
+ * queue.
+ */
+ class Queue{
+ std::string name;
+ const bool autodelete;
+ const bool exclusive;
+ bool durable;
+
+ public:
+
+ /**
+ * Creates an unnamed, non-durable, temporary queue. A name
+ * will be assigned to this queue instance by a call to
+ * Channel::declareQueue().
+ */
+ Queue();
+ /**
+ * Creates a shared, non-durable, queue with a given name,
+ * that will not be autodeleted.
+ *
+ * @param name the name of the queue
+ */
+ Queue(std::string name);
+ /**
+ * Creates a non-durable queue with a given name.
+ *
+ * @param name the name of the queue
+ *
+ * @param temp if true the queue will be a temporary queue, if
+ * false it will be shared and not autodeleted.
+ */
+ Queue(std::string name, bool temp);
+ /**
+ * This constructor allows the autodelete, exclusive and
+ * durable propeties to be explictly set. Note however that if
+ * exclusive is true, autodelete has no meaning as exclusive
+ * queues are always destroyed when the connection that
+ * created them is closed.
+ */
+ Queue(std::string name, bool autodelete, bool exclusive, bool durable);
+ const std::string& getName() const;
+ void setName(const std::string&);
+ bool isAutoDelete() const;
+ bool isExclusive() const;
+ bool isDurable() const;
+ void setDurable(bool durable);
+ };
+
+}
+}
+
+#endif /*!_client_Queue_h*/
diff --git a/qpid/cpp/src/qpid/client/Response.h b/qpid/cpp/src/qpid/client/Response.h
new file mode 100644
index 0000000000..2b7d55ec1f
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/Response.h
@@ -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.
+ *
+ */
+
+#ifndef _Response_
+#define _Response_
+
+#include <boost/shared_ptr.hpp>
+#include "qpid/framing/amqp_framing.h"
+#include "Completion.h"
+
+namespace qpid {
+namespace client {
+
+class Response : public Completion
+{
+public:
+ Response(Future f, shared_ptr<SessionCore> s) : Completion(f, s) {}
+
+ template <class T> T& as()
+ {
+ framing::AMQMethodBody* response(future.getResponse(*session));
+ return *boost::polymorphic_downcast<T*>(response);
+ }
+
+ template <class T> bool isA()
+ {
+ framing::AMQMethodBody* response(future.getResponse(*session));
+ return response && response->isA<T>();
+ }
+};
+
+}}
+
+#endif
diff --git a/qpid/cpp/src/qpid/client/Session.h b/qpid/cpp/src/qpid/client/Session.h
new file mode 100644
index 0000000000..5d91f289e2
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/Session.h
@@ -0,0 +1,38 @@
+#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_99_0.h"
+
+namespace qpid {
+namespace client {
+
+/**
+ * Session is currently just an alias for Session_99_0
+ *
+ * \ingroup clientapi
+ */
+typedef Session_99_0 Session;
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_SESSION_H*/
diff --git a/qpid/cpp/src/qpid/client/SessionBase.cpp b/qpid/cpp/src/qpid/client/SessionBase.cpp
new file mode 100644
index 0000000000..0e1fa67bda
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/SessionBase.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 "SessionBase.h"
+
+namespace qpid {
+namespace client {
+using namespace framing;
+
+SessionBase::SessionBase() {}
+SessionBase::~SessionBase() {}
+SessionBase::SessionBase(shared_ptr<SessionCore> core) : impl(core) {}
+void SessionBase::suspend() { impl->suspend(); }
+void SessionBase::close() { impl->close(); }
+
+void SessionBase::setSynchronous(bool isSync) { impl->setSync(isSync); }
+void SessionBase::setSynchronous(SynchronousMode m) { impl->setSync(m); }
+bool SessionBase::isSynchronous() const { return impl->isSync(); }
+SynchronousMode SessionBase::getSynchronous() const {
+ return SynchronousMode(impl->isSync());
+}
+
+Execution& SessionBase::getExecution() { return impl->getExecution(); }
+Uuid SessionBase::getId() const { return impl->getId(); }
+framing::FrameSet::shared_ptr SessionBase::get() { return impl->get(); }
+
+void SessionBase::sync() {
+ Execution& ex = getExecution();
+ ex.syncWait(ex.lastSent());
+ impl->assertOpen();
+}
+
+}} // namespace qpid::client
diff --git a/qpid/cpp/src/qpid/client/SessionBase.h b/qpid/cpp/src/qpid/client/SessionBase.h
new file mode 100644
index 0000000000..3565145bb9
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/SessionBase.h
@@ -0,0 +1,134 @@
+#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/framing/Uuid.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/Response.h"
+#include "qpid/client/SessionCore.h"
+#include "qpid/client/TypedResult.h"
+#include "qpid/shared_ptr.h"
+#include <string>
+
+namespace qpid {
+namespace client {
+
+using std::string;
+using framing::Content;
+using framing::FieldTable;
+using framing::MethodContent;
+using framing::SequenceNumberSet;
+using framing::Uuid;
+
+/** \defgroup clientapi Synchronous mode of a session.
+ *
+ * SYNC means that Session functions do not return until the remote
+ * broker has confirmed that the command was executed.
+ *
+ * ASYNC means that the client sends commands asynchronously, Session
+ * functions return immediately.
+ *
+ * ASYNC mode gives better performance for high-volume traffic, but
+ * requires some additional caution:
+ *
+ * Session functions return immediately. If the command causes an
+ * exception on the broker, the exception will be thrown on a
+ * <em>later</em> function call.
+ *
+ * If you need to notify some extenal agent that some actions have
+ * been taken (e.g. binding queues to exchanages), you must call
+ * Session::sync() first, to ensure that all the commands are complete.
+ *
+ * You can freely switch between modes by calling Session::setSynchronous()
+ *
+ * @see Session::sync(), Session::setSynchronous()
+ */
+enum SynchronousMode { SYNC=true, ASYNC=false };
+
+
+/**
+ * Basic session operations that are not derived from AMQP XML methods.
+ */
+class SessionBase
+{
+ public:
+ SessionBase();
+ ~SessionBase();
+
+ /** Get the next message frame-set from the session. */
+ framing::FrameSet::shared_ptr get();
+
+ /** Get the session ID */
+ Uuid getId() const;
+
+ /**
+ * In synchronous mode, wait for the broker's response before
+ * returning. Note this gives lower throughput than asynchronous
+ * mode.
+ *
+ * In asynchronous mode commands are sent without waiting
+ * for a respose (you can use the returned Completion object
+ * to wait for completion.)
+ *
+ * @see SynchronousMode
+ */
+ void setSynchronous(SynchronousMode mode);
+ void setSynchronous(bool set);
+ bool isSynchronous() const;
+ SynchronousMode getSynchronous() const;
+
+ /**
+ * Suspend the session, can be resumed on a different connection.
+ * @see Connection::resume()
+ */
+ void suspend();
+
+ /** Close the session */
+ void close();
+
+ /**
+ * Synchronize with the broker. Wait for all commands issued so far in
+ * the session to complete.
+ * @see SynchronousMode
+ */
+ void sync();
+
+ Execution& getExecution();
+
+ typedef framing::TransferContent DefaultContent;
+
+ protected:
+ shared_ptr<SessionCore> impl;
+ framing::ProtocolVersion version;
+ friend class Connection;
+ SessionBase(shared_ptr<SessionCore>);
+};
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_SESSIONBASE_H*/
diff --git a/qpid/cpp/src/qpid/client/SessionCore.cpp b/qpid/cpp/src/qpid/client/SessionCore.cpp
new file mode 100644
index 0000000000..5079c47b5e
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/SessionCore.cpp
@@ -0,0 +1,440 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "SessionCore.h"
+#include "Future.h"
+#include "FutureResponse.h"
+#include "FutureResult.h"
+#include "ConnectionImpl.h"
+#include "qpid/framing/FrameSet.h"
+#include "qpid/framing/constants.h"
+#include "qpid/framing/ClientInvoker.h"
+#include "qpid/log/Statement.h"
+
+#include <boost/bind.hpp>
+
+namespace qpid {
+namespace client {
+
+using namespace qpid::framing;
+
+namespace { const std::string OK="ok"; }
+
+typedef sys::Monitor::ScopedLock Lock;
+typedef sys::Monitor::ScopedUnlock UnLock;
+
+inline void SessionCore::invariant() const {
+ switch (state.get()) {
+ case OPENING:
+ assert(!session);
+ assert(code==REPLY_SUCCESS);
+ assert(connection);
+ assert(channel.get());
+ assert(channel.next == connection.get());
+ break;
+ case RESUMING:
+ assert(session);
+ assert(session->getState() == SessionState::RESUMING);
+ assert(code==REPLY_SUCCESS);
+ assert(connection);
+ assert(channel.get());
+ assert(channel.next == connection.get());
+ break;
+ case OPEN:
+ case CLOSING:
+ case SUSPENDING:
+ assert(session);
+ assert(connection);
+ assert(channel.get());
+ assert(channel.next == connection.get());
+ break;
+ case SUSPENDED:
+ assert(session);
+ assert(!connection);
+ break;
+ case CLOSED:
+ assert(!session);
+ assert(!connection);
+ break;
+ }
+}
+
+inline void SessionCore::setState(State s) {
+ state = s;
+ invariant();
+}
+
+inline void SessionCore::waitFor(State s) {
+ invariant();
+ // We can be CLOSED or SUSPENDED by error at any time.
+ state.waitFor(States(s, CLOSED, SUSPENDED));
+ check();
+ invariant();
+}
+
+SessionCore::SessionCore(shared_ptr<ConnectionImpl> conn,
+ uint16_t ch, uint64_t maxFrameSize)
+ : l3(maxFrameSize),
+ sync(false),
+ channel(ch),
+ proxy(channel),
+ state(OPENING),
+ detachedLifetime(0)
+{
+ l3.out = &out;
+ attaching(conn);
+}
+
+void SessionCore::attaching(shared_ptr<ConnectionImpl> c) {
+ assert(c);
+ assert(channel.get());
+ connection = c;
+ channel.next = connection.get();
+ code = REPLY_SUCCESS;
+ text = OK;
+ state = session ? RESUMING : OPENING;
+ invariant();
+}
+
+SessionCore::~SessionCore() {
+ Lock l(state);
+ detach(COMMAND_INVALID, "Session deleted");
+ state.waitWaiters();
+}
+
+void SessionCore::detach(int c, const std::string& t) {
+ connection.reset();
+ channel.next = 0;
+ code=c;
+ text=t;
+ l3.getDemux().close();
+}
+
+void SessionCore::doClose(int code, const std::string& text) {
+ if (state != CLOSED) {
+ session.reset();
+ detach(code, text);
+ setState(CLOSED);
+ l3.getCompletionTracker().close();
+ }
+ invariant();
+}
+
+void SessionCore::doSuspend(int code, const std::string& text) {
+ if (state != CLOSED && state != SUSPENDED) {
+ detach(code, text);
+ session->suspend();
+ setState(SUSPENDED);
+ }
+ invariant();
+}
+
+ExecutionHandler& SessionCore::getExecution() { // user thread
+ return l3;
+}
+
+void SessionCore::setSync(bool s) { // user thread
+ sync = s;
+}
+
+bool SessionCore::isSync() { // user thread
+ return sync;
+}
+
+FrameSet::shared_ptr SessionCore::get() { // user thread
+ // No lock here: pop does a blocking wait.
+ return l3.getDemux().getDefault()->pop();
+}
+
+static const std::string CANNOT_REOPEN_SESSION="Cannot re-open a session.";
+
+void SessionCore::open(uint32_t timeout) { // user thread
+ Lock l(state);
+ check(state==OPENING && !session,
+ COMMAND_INVALID, CANNOT_REOPEN_SESSION);
+ detachedLifetime=timeout;
+ proxy.open(detachedLifetime);
+ waitFor(OPEN);
+}
+
+void SessionCore::close() { // user thread
+ Lock l(state);
+ check();
+ if (state==OPEN) {
+ setState(CLOSING);
+ proxy.close();
+ waitFor(CLOSED);
+ }
+ else
+ doClose(REPLY_SUCCESS, OK);
+}
+
+void SessionCore::suspend() { // user thread
+ Lock l(state);
+ checkOpen();
+ setState(SUSPENDING);
+ proxy.suspend();
+ waitFor(SUSPENDED);
+}
+
+void SessionCore::setChannel(uint16_t ch) { channel=ch; }
+
+static const std::string CANNOT_RESUME_SESSION("Session cannot be resumed.");
+
+void SessionCore::resume(shared_ptr<ConnectionImpl> c) {
+ // user thread
+ {
+ Lock l(state);
+ if (state==SUSPENDED) { // Clear error that caused suspend
+ code=REPLY_SUCCESS;
+ text=OK;
+ }
+ check(state==SUSPENDED, COMMAND_INVALID, CANNOT_RESUME_SESSION);
+ SequenceNumber sendAck=session->resuming();
+ attaching(c);
+ proxy.resume(getId());
+ waitFor(OPEN);
+ proxy.ack(sendAck, SequenceNumberSet());
+ // TODO aconway 2007-10-23: Replay inside the lock might be a prolem
+ // for large replay sets.
+ SessionState::Replay replay=session->replay();
+ for (SessionState::Replay::iterator i = replay.begin();
+ i != replay.end(); ++i)
+ {
+ invariant();
+ channel.handle(*i); // Direct to channel.
+ check();
+ }
+ l3.getDemux().open();
+ }
+}
+
+void SessionCore::assertOpen() const {
+ Lock l(state);
+ checkOpen();
+}
+
+static const std::string UNEXPECTED_SESSION_ATTACHED(
+ "Received unexpected session.attached");
+
+static const std::string INVALID_SESSION_RESUME_ID(
+ "session.resumed has invalid ID.");
+
+// network thread
+void SessionCore::attached(const Uuid& sessionId,
+ uint32_t /*detachedLifetime*/)
+{
+ Lock l(state);
+ invariant();
+ check(state == OPENING || state == RESUMING,
+ COMMAND_INVALID, UNEXPECTED_SESSION_ATTACHED);
+ if (state==OPENING) { // New session
+ // TODO aconway 2007-10-17: 0 disables sesskon.ack for now.
+ // If AMQP WG decides to keep it, we need to add configuration
+ // for the ack rate.
+ session=in_place<SessionState>(0, detachedLifetime > 0, sessionId);
+ setState(OPEN);
+ }
+ else { // RESUMING
+ check(sessionId == session->getId(),
+ INVALID_ARGUMENT, INVALID_SESSION_RESUME_ID);
+ // Don't setState yet, wait for first incoming ack.
+ }
+}
+
+static const std::string UNEXPECTED_SESSION_DETACHED(
+ "Received unexpected session.detached.");
+
+static const std::string UNEXPECTED_SESSION_ACK(
+ "Received unexpected session.ack");
+
+void SessionCore::detached() { // network thread
+ Lock l(state);
+ check(state == SUSPENDING,
+ COMMAND_INVALID, UNEXPECTED_SESSION_DETACHED);
+ doSuspend(REPLY_SUCCESS, OK);
+}
+
+void SessionCore::ack(uint32_t ack, const SequenceNumberSet&) {
+ Lock l(state);
+ invariant();
+ check(state==OPEN || state==RESUMING,
+ COMMAND_INVALID, UNEXPECTED_SESSION_ACK);
+ session->receivedAck(ack);
+ if (state==RESUMING) {
+ setState(OPEN);
+ }
+ invariant();
+}
+
+void SessionCore::closed(uint16_t code, const std::string& text)
+{ // network thread
+ Lock l(state);
+ invariant();
+ doClose(code, text);
+}
+
+// closed by connection
+void SessionCore::connectionClosed(uint16_t code, const std::string& text) {
+ Lock l(state);
+ try {
+ doClose(code, text);
+ } catch(...) { assert (0); }
+}
+
+void SessionCore::connectionBroke(uint16_t code, const std::string& text) {
+ Lock l(state);
+ try {
+ doSuspend(code, text);
+ } catch (...) { assert(0); }
+}
+
+void SessionCore::check() const { // Called with lock held.
+ invariant();
+ if (code != REPLY_SUCCESS)
+ throwReplyException(code, text);
+}
+
+void SessionCore::check(bool cond, int newCode, const std::string& msg) const {
+ check();
+ if (!cond) {
+ const_cast<SessionCore*>(this)->doClose(newCode, msg);
+ throwReplyException(code, text);
+ }
+}
+
+static const std::string SESSION_NOT_OPEN("Session is not open");
+
+void SessionCore::checkOpen() const {
+ if (state==SUSPENDED) {
+ std::string cause;
+ if (code != REPLY_SUCCESS)
+ cause=" by :"+text;
+ throw CommandInvalidException(QPID_MSG("Session is suspended" << cause));
+ }
+ check(state==OPEN, COMMAND_INVALID, SESSION_NOT_OPEN);
+}
+
+Future SessionCore::send(const AMQBody& command)
+{
+ Lock l(state);
+ checkOpen();
+ command.getMethod()->setSync(sync);
+ Future f;
+ //any result/response listeners must be set before the command is sent
+ if (command.getMethod()->resultExpected()) {
+ boost::shared_ptr<FutureResult> r(new FutureResult());
+ f.setFutureResult(r);
+ //result listener is tied to command id, and is set when that
+ //is allocated by the execution handler, so pass it to send
+ f.setCommandId(l3.send(command, boost::bind(&FutureResult::received, r, _1)));
+ } else {
+ if (command.getMethod()->responseExpected()) {
+ boost::shared_ptr<FutureResponse> r(new FutureResponse());
+ f.setFutureResponse(r);
+ l3.getCorrelator().listen(boost::bind(&FutureResponse::received, r, _1));
+ }
+
+ f.setCommandId(l3.send(command));
+ }
+ return f;
+}
+
+Future SessionCore::send(const AMQBody& command, const MethodContent& content)
+{
+ Lock l(state);
+ checkOpen();
+ //content bearing methods don't currently have responses or
+ //results, if that changes should follow procedure for the other
+ //send method impl:
+ return Future(l3.send(command, content));
+}
+
+namespace {
+bool isCloseResponse(const AMQFrame& frame) {
+ return frame.getMethod() &&
+ frame.getMethod()->amqpClassId() == SESSION_CLASS_ID &&
+ frame.getMethod()->amqpMethodId() == SESSION_CLOSED_METHOD_ID;
+}
+}
+
+// Network thread.
+void SessionCore::handleIn(AMQFrame& frame) {
+ ConnectionImpl::shared_ptr save;
+ {
+ Lock l(state);
+ save=connection;
+ // Ignore frames received while closing other than closed response.
+ if (state==CLOSING && !isCloseResponse(frame))
+ return;
+ }
+ try {
+ // Cast to expose private SessionHandler functions.
+ if (invoke(static_cast<SessionHandler&>(*this), *frame.getBody())) {
+ // If we were detached by a session command, tell the connection.
+ if (!connection) save->erase(channel);
+ }
+ else {
+ session->received(frame);
+ l3.handle(frame);
+ }
+ } catch (const ChannelException& e) {
+ QPID_LOG(error, "Channel exception:" << e.what());
+ doClose(e.code, e.what());
+ }
+}
+
+void SessionCore::handleOut(AMQFrame& frame)
+{
+ Lock l(state);
+ if (state==OPEN) {
+ if (detachedLifetime > 0 && session->sent(frame))
+ proxy.solicitAck();
+ channel.handle(frame);
+ }
+}
+
+void SessionCore::solicitAck( ) {
+ Lock l(state);
+ checkOpen();
+ proxy.ack(session->sendingAck(), SequenceNumberSet());
+}
+
+void SessionCore::flow(bool) {
+ assert(0); throw NotImplementedException("session.flow");
+}
+
+void SessionCore::flowOk(bool /*active*/) {
+ assert(0); throw NotImplementedException("session.flow");
+}
+
+void SessionCore::highWaterMark(uint32_t /*lastSentMark*/) {
+ // TODO aconway 2007-10-02: may be removed from spec.
+ assert(0); throw NotImplementedException("session.highWaterMark");
+}
+
+const Uuid SessionCore::getId() const {
+ if (session)
+ return session->getId();
+ throw Exception(QPID_MSG("Closed session, no ID."));
+}
+
+}} // namespace qpid::client
diff --git a/qpid/cpp/src/qpid/client/SessionCore.h b/qpid/cpp/src/qpid/client/SessionCore.h
new file mode 100644
index 0000000000..2bb0f41fbf
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/SessionCore.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 _SessionCore_
+#define _SessionCore_
+
+#include "qpid/shared_ptr.h"
+#include "qpid/framing/FrameHandler.h"
+#include "qpid/framing/ChannelHandler.h"
+#include "qpid/framing/SessionState.h"
+#include "qpid/framing/SequenceNumber.h"
+#include "qpid/framing/AMQP_ClientOperations.h"
+#include "qpid/framing/AMQP_ServerProxy.h"
+#include "qpid/sys/StateMonitor.h"
+#include "ExecutionHandler.h"
+
+#include <boost/optional.hpp>
+
+namespace qpid {
+namespace framing {
+class FrameSet;
+class MethodContent;
+class SequenceNumberSet;
+}
+
+namespace client {
+
+class Future;
+class ConnectionImpl;
+
+/**
+ * Session implementation, sets up handler chains.
+ * Attaches to a SessionHandler when active, detaches
+ * when closed.
+ */
+class SessionCore : public framing::FrameHandler::InOutHandler,
+ private framing::AMQP_ClientOperations::SessionHandler
+{
+ public:
+ SessionCore(shared_ptr<ConnectionImpl>, uint16_t channel, uint64_t maxFrameSize);
+ ~SessionCore();
+
+ framing::FrameSet::shared_ptr get();
+ const framing::Uuid getId() const;
+ uint16_t getChannel() const { return channel; }
+ void assertOpen() const;
+
+ // NOTE: Public functions called in user thread.
+ void open(uint32_t detachedLifetime);
+ void close();
+ void resume(shared_ptr<ConnectionImpl>);
+ void suspend();
+ void setChannel(uint16_t channel);
+
+ void setSync(bool s);
+ bool isSync();
+ ExecutionHandler& getExecution();
+
+ Future send(const framing::AMQBody& command);
+
+ Future send(const framing::AMQBody& command, const framing::MethodContent& content);
+
+ void connectionClosed(uint16_t code, const std::string& text);
+ void connectionBroke(uint16_t code, const std::string& text);
+
+ private:
+ enum State {
+ OPENING,
+ RESUMING,
+ OPEN,
+ CLOSING,
+ SUSPENDING,
+ SUSPENDED,
+ CLOSED
+ };
+ typedef framing::AMQP_ClientOperations::SessionHandler SessionHandler;
+ typedef sys::StateMonitor<State, CLOSED> StateMonitor;
+ typedef StateMonitor::Set States;
+
+ inline void invariant() const;
+ inline void setState(State s);
+ inline void waitFor(State);
+ void doClose(int code, const std::string& text);
+ void doSuspend(int code, const std::string& text);
+
+ /** If there is an error, throw the exception */
+ void check(bool condition, int code, const std::string& text) const;
+ /** Throw if *error */
+ void check() const;
+
+ void handleIn(framing::AMQFrame& frame);
+ void handleOut(framing::AMQFrame& frame);
+
+ // Private functions are called by broker in network thread.
+ void attached(const framing::Uuid& sessionId, uint32_t detachedLifetime);
+ void flow(bool active);
+ void flowOk(bool active);
+ void detached();
+ void ack(uint32_t cumulativeSeenMark,
+ const framing::SequenceNumberSet& seenFrameSet);
+ void highWaterMark(uint32_t lastSentMark);
+ void solicitAck();
+ void closed(uint16_t code, const std::string& text);
+
+ void attaching(shared_ptr<ConnectionImpl>);
+ void detach(int code, const std::string& text);
+ void checkOpen() const;
+
+ int code; // Error code
+ std::string text; // Error text
+ boost::optional<framing::SessionState> session;
+ shared_ptr<ConnectionImpl> connection;
+ ExecutionHandler l3;
+ volatile bool sync;
+ framing::ChannelHandler channel;
+ framing::AMQP_ServerProxy::Session proxy;
+ mutable StateMonitor state;
+ uint32_t detachedLifetime;
+};
+
+}} // namespace qpid::client
+
+#endif
diff --git a/qpid/cpp/src/qpid/client/StateManager.cpp b/qpid/cpp/src/qpid/client/StateManager.cpp
new file mode 100644
index 0000000000..0cb3c6b9d4
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/client/StateManager.h b/qpid/cpp/src/qpid/client/StateManager.h
new file mode 100644
index 0000000000..2f8ecb772c
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/StateManager.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 _StateManager_
+#define _StateManager_
+
+#include <set>
+#include "qpid/sys/Monitor.h"
+
+namespace qpid {
+namespace client {
+
+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/qpid/cpp/src/qpid/client/SubscriptionManager.cpp b/qpid/cpp/src/qpid/client/SubscriptionManager.cpp
new file mode 100644
index 0000000000..f14344225c
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/SubscriptionManager.cpp
@@ -0,0 +1,111 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 <qpid/client/Dispatcher.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/MessageListener.h>
+#include <set>
+#include <sstream>
+
+
+namespace qpid {
+namespace client {
+
+SubscriptionManager::SubscriptionManager(Session& s)
+ : dispatcher(s), session(s),
+ messages(UNLIMITED), bytes(UNLIMITED), window(true),
+ confirmMode(true), acquireMode(false),
+ autoStop(true)
+{}
+
+Completion SubscriptionManager::subscribeInternal(
+ const std::string& q, const std::string& dest)
+{
+ Completion c = session.messageSubscribe(arg::queue=q, arg::destination=dest,
+ arg::confirmMode=confirmMode, arg::acquireMode=acquireMode);
+ setFlowControl(dest, messages, bytes, window);
+ return c;
+}
+
+Completion SubscriptionManager::subscribe(
+ MessageListener& listener, const std::string& q, const std::string& d)
+{
+ std::string dest=d.empty() ? q:d;
+ dispatcher.listen(dest, &listener, autoAck);
+ return subscribeInternal(q, dest);
+}
+
+Completion SubscriptionManager::subscribe(
+ LocalQueue& lq, const std::string& q, const std::string& d)
+{
+ std::string dest=d.empty() ? q:d;
+ lq.session=session;
+ lq.queue=session.getExecution().getDemux().add(dest, ByTransferDest(dest));
+ return subscribeInternal(q, dest);
+}
+
+void SubscriptionManager::setFlowControl(
+ const std::string& dest, uint32_t messages, uint32_t bytes, bool window)
+{
+ session.messageFlowMode(dest, window);
+ session.messageFlow(dest, 0, messages);
+ session.messageFlow(dest, 1, bytes);
+}
+
+void SubscriptionManager::setFlowControl(
+ uint32_t messages_, uint32_t bytes_, bool window_)
+{
+ messages=messages_;
+ bytes=bytes_;
+ window=window_;
+}
+
+void SubscriptionManager::setConfirmMode(bool c) { confirmMode=c; }
+
+void SubscriptionManager::setAcquireMode(bool a) { acquireMode=a; }
+
+void SubscriptionManager::setAckPolicy(const AckPolicy& a) { autoAck=a; }
+
+void SubscriptionManager::cancel(const std::string dest)
+{
+ dispatcher.cancel(dest);
+ session.messageCancel(dest);
+}
+
+void SubscriptionManager::setAutoStop(bool set) { autoStop=set; }
+
+void SubscriptionManager::run()
+{
+ dispatcher.setAutoStop(autoStop);
+ dispatcher.run();
+}
+
+void SubscriptionManager::stop()
+{
+ dispatcher.stop();
+}
+
+}} // namespace qpid::client
+
+#endif
diff --git a/qpid/cpp/src/qpid/client/SubscriptionManager.h b/qpid/cpp/src/qpid/client/SubscriptionManager.h
new file mode 100644
index 0000000000..1741796f4f
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/SubscriptionManager.h
@@ -0,0 +1,141 @@
+#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/MessageListener.h>
+#include <qpid/client/LocalQueue.h>
+#include <qpid/sys/Runnable.h>
+
+#include <set>
+#include <sstream>
+
+namespace qpid {
+namespace client {
+
+/**
+ * Utility to assist with creating subscriptions.
+ *
+ * \ingroup clientapi
+ */
+class SubscriptionManager : public sys::Runnable
+{
+ typedef sys::Mutex::ScopedLock Lock;
+ typedef sys::Mutex::ScopedUnlock Unlock;
+
+ Completion subscribeInternal(const std::string& q, const std::string& dest);
+
+ qpid::client::Dispatcher dispatcher;
+ qpid::client::Session& session;
+ uint32_t messages;
+ uint32_t bytes;
+ bool window;
+ AckPolicy autoAck;
+ bool confirmMode;
+ bool acquireMode;
+ bool autoStop;
+
+ public:
+ SubscriptionManager(Session& session);
+
+ /**
+ * Subscribe a MessagesListener to receive messages from queue.
+ *
+ *@param listener Listener object to receive messages.
+ *@param queue Name of the queue to subscribe to.
+ *@param tag Unique destination tag for the listener.
+ * If not specified, the queue name is used.
+ */
+ Completion subscribe(MessageListener& listener,
+ const std::string& queue,
+ const std::string& tag=std::string());
+
+ /**
+ * Subscribe a LocalQueue to receive messages from queue.
+ *
+ *@param queue Name of the queue to subscribe to.
+ *@param tag Unique destination tag for the listener.
+ * If not specified, the queue name is used.
+ */
+ Completion subscribe(LocalQueue& localQueue,
+ const std::string& queue,
+ const std::string& tag=std::string());
+
+ /** Cancel a subscription. */
+ void cancel(const std::string tag);
+
+ /** Deliver messages until stop() is called. */
+ void run();
+
+ /** 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);
+
+ /** Cause run() to return */
+ void stop();
+
+
+ static const uint32_t UNLIMITED=0xFFFFFFFF;
+
+ /** Set the flow control for destination tag.
+ *@param tag: name of the destination.
+ *@param messages: message credit.
+ *@param bytes: byte credit.
+ *@param window: if true use window-based flow control.
+ */
+ void setFlowControl(const std::string& tag, uint32_t messages, uint32_t bytes, bool window=true);
+
+ /** Set the initial flow control settings to be applied to each new subscribtion.
+ *@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);
+
+ /** Set the confirm-mode for new subscriptions. Defaults to true.
+ *@param confirm: if true messages must be confirmed by calling
+ *Message::acknowledge() or automatically, see setAckPolicy()
+ */
+ void setConfirmMode(bool confirm);
+
+ /** Set the acquire-mode for new subscriptions. Defaults to false.
+ *@param acquire: if false messages pre-acquired, if true
+ * messages are dequed on acknowledgement or on transfer
+ * depending on confirmMode.
+ */
+ void setAcquireMode(bool acquire);
+
+ /** Set the acknowledgement policy for new subscriptions.
+ * Default is to acknowledge every message automatically.
+ */
+ void setAckPolicy(const AckPolicy& autoAck);
+};
+
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_SUBSCRIPTIONMANAGER_H*/
diff --git a/qpid/cpp/src/qpid/client/TypedResult.h b/qpid/cpp/src/qpid/client/TypedResult.h
new file mode 100644
index 0000000000..edcf728c54
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/TypedResult.h
@@ -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.
+ *
+ */
+
+#ifndef _TypedResult_
+#define _TypedResult_
+
+#include "Completion.h"
+
+namespace qpid {
+namespace client {
+
+template <class T> class TypedResult : public Completion
+{
+ T result;
+ bool decoded;
+
+public:
+ TypedResult(Future f, shared_ptr<SessionCore> s) : Completion(f, s), decoded(false) {}
+
+ T& get()
+ {
+ if (!decoded) {
+ future.decodeResult(result, *session);
+ decoded = true;
+ }
+
+ return result;
+ }
+};
+
+}}
+
+#endif
diff --git a/qpid/cpp/src/qpid/cluster/ClassifierHandler.cpp b/qpid/cpp/src/qpid/cluster/ClassifierHandler.cpp
new file mode 100644
index 0000000000..a4ea257f0c
--- /dev/null
+++ b/qpid/cpp/src/qpid/cluster/ClassifierHandler.cpp
@@ -0,0 +1,51 @@
+/*
+ *
+ * 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 "ClassifierHandler.h"
+
+#include "qpid/framing/FrameDefaultVisitor.h"
+#include "qpid/framing/AMQFrame.h"
+
+namespace qpid {
+namespace cluster {
+
+using namespace framing;
+
+struct ClassifierHandler::Visitor : public FrameDefaultVisitor {
+ Visitor(AMQFrame& f, ClassifierHandler& c)
+ : chosen(0), frame(f), classifier(c) { f.getBody()->accept(*this); }
+
+ void visit(const ExchangeDeclareBody&) { chosen=&classifier.wiring; }
+ void visit(const ExchangeDeleteBody&) { chosen=&classifier.wiring; }
+ void visit(const QueueBindBody&) { chosen=&classifier.wiring; }
+ void visit(const QueueDeclareBody&) { chosen=&classifier.wiring; }
+ void visit(const QueueDeleteBody&) { chosen=&classifier.wiring; }
+ void visit(const QueueUnbindBody&) { chosen=&classifier.wiring; }
+ void defaultVisit(const AMQBody&) { chosen=&classifier.other; }
+
+ using framing::FrameDefaultVisitor::visit;
+ using framing::FrameDefaultVisitor::defaultVisit;
+
+ FrameHandler::Chain chosen;
+ AMQFrame& frame;
+ ClassifierHandler& classifier;
+};
+
+void ClassifierHandler::handle(AMQFrame& f) { Visitor(f, *this).chosen(f); }
+
+}} // namespace qpid::cluster
diff --git a/qpid/cpp/src/qpid/cluster/ClassifierHandler.h b/qpid/cpp/src/qpid/cluster/ClassifierHandler.h
new file mode 100644
index 0000000000..696e457c04
--- /dev/null
+++ b/qpid/cpp/src/qpid/cluster/ClassifierHandler.h
@@ -0,0 +1,50 @@
+#ifndef QPID_CLUSTER_CLASSIFIERHANDLER_H
+#define QPID_CLUSTER_CLASSIFIERHANDLER_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/framing/FrameHandler.h"
+
+namespace qpid {
+namespace cluster {
+
+/**
+ * Classify frames and forward to the appropriate handler.
+ */
+class ClassifierHandler : public framing::FrameHandler
+{
+ public:
+ ClassifierHandler(framing::FrameHandler& wiring_,
+ framing::FrameHandler& other_)
+ : wiring(wiring_), other(other_) {}
+
+ void handle(framing::AMQFrame&);
+
+ private:
+ struct Visitor;
+ friend struct Visitor;
+ framing::FrameHandler& wiring;
+ framing::FrameHandler& other;
+};
+
+}} // namespace qpid::cluster
+
+
+
+#endif /*!QPID_CLUSTER_CLASSIFIERHANDLER_H*/
diff --git a/qpid/cpp/src/qpid/cluster/Cluster.cpp b/qpid/cpp/src/qpid/cluster/Cluster.cpp
new file mode 100644
index 0000000000..5152aa2e43
--- /dev/null
+++ b/qpid/cpp/src/qpid/cluster/Cluster.cpp
@@ -0,0 +1,260 @@
+/*
+ *
+ * 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 "qpid/broker/PreviewSessionState.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/ClusterNotifyBody.h"
+#include "qpid/log/Statement.h"
+#include <boost/bind.hpp>
+#include <boost/scoped_array.hpp>
+#include <algorithm>
+#include <iterator>
+#include <map>
+
+namespace qpid {
+namespace cluster {
+using namespace qpid::framing;
+using namespace qpid::sys;
+using namespace std;
+using broker::PreviewSessionState;
+
+namespace {
+
+// Beginning of inbound chain: send to cluster.
+struct ClusterSendHandler : public FrameHandler {
+ PreviewSessionState& session;
+ Cluster& cluster;
+ bool busy;
+ Monitor lock;
+
+ ClusterSendHandler(PreviewSessionState& s, Cluster& c) : session(s), cluster(c), busy(false) {}
+
+ void handle(AMQFrame& f) {
+ Mutex::ScopedLock l(lock);
+ assert(!busy);
+ // FIXME aconway 2008-01-29: refcount Sessions.
+ // session.addRef(); // Keep the session till the message is self delivered.
+ cluster.send(f, next); // Indirectly send to next via cluster.
+
+ // FIXME aconway 2008-01-29: need to get this blocking out of the loop.
+ // But cluster needs to agree on order of side-effects on the shared model.
+ // OK for wiring to block, for messages use queue tokens?
+ // Both in & out transfers must be orderd per queue.
+ // May need out-of-order completion.
+ busy=true;
+ while (busy) lock.wait();
+ }
+};
+
+// Next in inbound chain, self delivered from cluster.
+struct ClusterDeliverHandler : public FrameHandler {
+ Cluster& cluster;
+ ClusterSendHandler& sender;
+
+ ClusterDeliverHandler(ClusterSendHandler& prev, Cluster& c) : cluster(c), sender(prev) {}
+
+ void handle(AMQFrame& f) {
+ next->handle(f);
+ Mutex::ScopedLock l(sender.lock);
+ sender.busy=false;
+ sender.lock.notify();
+ }
+};
+
+// FIXME aconway 2008-01-29: IList
+void insert(FrameHandler::Chain& c, FrameHandler* h) {
+ h->next = c.next;
+ c.next = h;
+}
+
+struct SessionObserver : public broker::PreviewSessionManager::Observer {
+ Cluster& cluster;
+ SessionObserver(Cluster& c) : cluster(c) {}
+
+ void opened(PreviewSessionState& s) {
+ // FIXME aconway 2008-01-29: IList for memory management.
+ ClusterSendHandler* sender=new ClusterSendHandler(s, cluster);
+ ClusterDeliverHandler* deliverer=new ClusterDeliverHandler(*sender, cluster);
+ insert(s.in, deliverer);
+ insert(s.in, sender);
+ }
+};
+}
+
+ostream& operator <<(ostream& out, const Cluster& cluster) {
+ return out << "cluster[" << cluster.name.str() << " " << cluster.self << "]";
+}
+
+ostream& operator<<(ostream& out, const Cluster::MemberMap::value_type& m) {
+ return out << m.first << "=" << m.second.url;
+}
+
+ostream& operator <<(ostream& out, const Cluster::MemberMap& members) {
+ ostream_iterator<Cluster::MemberMap::value_type> o(out, " ");
+ copy(members.begin(), members.end(), o);
+ return out;
+}
+
+Cluster::Cluster(const std::string& name_, const Url& url_, broker::Broker&) :
+ cpg(*this),
+ name(name_),
+ url(url_),
+ observer(new SessionObserver(*this))
+{
+ QPID_LOG(trace, *this << " Joining cluster: " << name_);
+ cpg.join(name);
+ notify();
+ dispatcher=Thread(*this);
+ // Wait till we show up in the cluster map.
+ {
+ Mutex::ScopedLock l(lock);
+ while (empty())
+ lock.wait();
+ }
+}
+
+Cluster::~Cluster() {
+ QPID_LOG(trace, *this << " Leaving cluster.");
+ try {
+ cpg.leave(name);
+ dispatcher.join();
+ }
+ catch (const std::exception& e) {
+ QPID_LOG(error, "Exception leaving cluster " << *this << ": "
+ << e.what());
+ }
+}
+
+void Cluster::send(AMQFrame& frame, FrameHandler* next) {
+ QPID_LOG(trace, *this << " SEND: " << frame);
+ char data[65536]; // FIXME aconway 2008-01-29: Better buffer handling.
+ Buffer buf(data);
+ frame.encode(buf);
+ buf.putRawData((uint8_t*)&next, sizeof(next)); // Tag the frame with the next pointer.
+ iovec iov = { data, frame.size()+sizeof(next) };
+ cpg.mcast(name, &iov, 1);
+}
+
+void Cluster::notify() {
+ AMQFrame frame(in_place<ClusterNotifyBody>(ProtocolVersion(), url.str()));
+ send(frame, 0);
+}
+
+size_t Cluster::size() const {
+ Mutex::ScopedLock l(lock);
+ return members.size();
+}
+
+Cluster::MemberList Cluster::getMembers() const {
+ Mutex::ScopedLock l(lock);
+ MemberList result(members.size());
+ std::transform(members.begin(), members.end(), result.begin(),
+ boost::bind(&MemberMap::value_type::second, _1));
+ return result;
+}
+
+void Cluster::deliver(
+ cpg_handle_t /*handle*/,
+ cpg_name* /*group*/,
+ uint32_t nodeid,
+ uint32_t pid,
+ void* msg,
+ int msg_len)
+{
+ try {
+ Id from(nodeid, pid);
+ Buffer buf(static_cast<char*>(msg), msg_len);
+ AMQFrame frame;
+ frame.decode(buf);
+ QPID_LOG(trace, *this << " RECV: " << frame << " from: " << from);
+ if (frame.getChannel() == 0)
+ handleClusterFrame(from, frame);
+ else if (from == self) {
+ FrameHandler* next;
+ buf.getRawData((uint8_t*)&next, sizeof(next));
+ next->handle(frame);
+ }
+ // FIXME aconway 2008-01-30: apply frames from foreign sessions.
+ }
+ catch (const std::exception& e) {
+ // FIXME aconway 2008-01-30: exception handling.
+ QPID_LOG(error, "Error handling frame from cluster " << e.what());
+ }
+}
+
+bool Cluster::wait(boost::function<bool(const Cluster&)> predicate,
+ Duration timeout) const
+{
+ AbsTime deadline(now(), timeout);
+ Mutex::ScopedLock l(lock);
+ while (!predicate(*this) && lock.wait(deadline))
+ ;
+ return (predicate(*this));
+}
+
+// Handle cluster control frame from the null session.
+void Cluster::handleClusterFrame(Id from, AMQFrame& frame) {
+ // TODO aconway 2007-06-20: use visitor pattern here.
+ ClusterNotifyBody* notifyIn=
+ dynamic_cast<ClusterNotifyBody*>(frame.getBody());
+ assert(notifyIn);
+ MemberList list;
+ {
+ Mutex::ScopedLock l(lock);
+ members[from].url=notifyIn->getUrl();
+ if (!self.id && notifyIn->getUrl() == url.str())
+ self=from;
+ lock.notifyAll();
+ QPID_LOG(trace, *this << ": members joined: " << members);
+ }
+}
+
+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)
+{
+ bool newMembers=false;
+ MemberList updated;
+ {
+ Mutex::ScopedLock l(lock);
+ if (nLeft) {
+ for (int i = 0; i < nLeft; ++i)
+ members.erase(Id(left[i]));
+ QPID_LOG(trace, *this << ": members left: " << members);
+ lock.notifyAll();
+ }
+ newMembers = nJoined > 1 || (nJoined==1 && Id(joined[0]) != self);
+ // We don't record members joining here, we record them when
+ // we get their ClusterNotify message.
+ }
+ if (newMembers) // Notify new members of my presence.
+ notify();
+}
+
+void Cluster::run() {
+ cpg.dispatchBlocking();
+}
+
+}} // namespace qpid::cluster
+
+
+
diff --git a/qpid/cpp/src/qpid/cluster/Cluster.h b/qpid/cpp/src/qpid/cluster/Cluster.h
new file mode 100644
index 0000000000..1b0c1b1689
--- /dev/null
+++ b/qpid/cpp/src/qpid/cluster/Cluster.h
@@ -0,0 +1,131 @@
+#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 "qpid/broker/Broker.h"
+#include "qpid/sys/Monitor.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/sys/Thread.h"
+#include "qpid/log/Logger.h"
+#include "qpid/Url.h"
+
+
+#include <boost/optional.hpp>
+#include <boost/function.hpp>
+#include <boost/intrusive_ptr.hpp>
+
+#include <map>
+#include <vector>
+
+namespace qpid { namespace cluster {
+
+/**
+ * Connection to the cluster.
+ * Keeps cluster membership data.
+ */
+class Cluster : private sys::Runnable, private Cpg::Handler
+{
+ public:
+ /** Details of a cluster member */
+ struct Member {
+ Member(const Url& url_=Url()) : url(url_) {}
+ Url url; ///< Broker address.
+ };
+
+ typedef std::vector<Member> MemberList;
+
+ /**
+ * Join a cluster.
+ * @param name of the cluster.
+ * @param url of this broker, sent to the cluster.
+ */
+ Cluster(const std::string& name, const Url& url, broker::Broker&);
+
+ virtual ~Cluster();
+
+ // FIXME aconway 2008-01-29:
+ boost::intrusive_ptr<broker::PreviewSessionManager::Observer> getObserver() { return observer; }
+
+ /** Get the current cluster membership. */
+ MemberList getMembers() const;
+
+ /** Number of members in the cluster. */
+ size_t size() const;
+
+ bool empty() const { return size() == 0; }
+
+ /** Wait for predicate(*this) to be true, up to timeout.
+ *@return True if predicate became true, false if timed out.
+ *Note the predicate may not be true after wait returns,
+ *all the caller can say is it was true at some earlier point.
+ */
+ bool wait(boost::function<bool(const Cluster&)> predicate,
+ sys::Duration timeout=sys::TIME_INFINITE) const;
+
+ /** Send frame to the cluster */
+ void send(framing::AMQFrame&, framing::FrameHandler*);
+
+ private:
+ typedef Cpg::Id Id;
+ typedef std::map<Id, Member> MemberMap;
+
+ void notify(); ///< Notify cluster of my details.
+
+ void deliver(
+ cpg_handle_t /*handle*/,
+ struct cpg_name *group,
+ uint32_t /*nodeid*/,
+ uint32_t /*pid*/,
+ void* /*msg*/,
+ int /*msg_len*/);
+
+ 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*/
+ );
+
+ void run();
+ void handleClusterFrame(Id from, framing::AMQFrame&);
+
+ mutable sys::Monitor lock;
+ Cpg cpg;
+ Cpg::Name name;
+ Url url;
+ Id self;
+ MemberMap members;
+ sys::Thread dispatcher;
+ boost::function<void()> callback;
+ boost::intrusive_ptr<broker::PreviewSessionManager::Observer> observer;
+
+ friend std::ostream& operator <<(std::ostream&, const Cluster&);
+ friend std::ostream& operator <<(std::ostream&, const MemberMap::value_type&);
+ friend std::ostream& operator <<(std::ostream&, const MemberMap&);
+};
+
+}} // namespace qpid::cluster
+
+
+
+#endif /*!QPID_CLUSTER_CLUSTER_H*/
diff --git a/qpid/cpp/src/qpid/cluster/ClusterPlugin.cpp b/qpid/cpp/src/qpid/cluster/ClusterPlugin.cpp
new file mode 100644
index 0000000000..0ea3953175
--- /dev/null
+++ b/qpid/cpp/src/qpid/cluster/ClusterPlugin.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 <boost/program_options/value_semantic.hpp>
+
+
+
+#include "qpid/broker/Broker.h"
+#include "qpid/cluster/Cluster.h"
+#include "qpid/Plugin.h"
+#include "qpid/Options.h"
+#include "qpid/shared_ptr.h"
+
+#include <boost/optional.hpp>
+#include <boost/utility/in_place_factory.hpp>
+
+
+namespace qpid {
+namespace cluster {
+
+using namespace std;
+
+struct ClusterOptions : public Options {
+ string name;
+ string url;
+
+ ClusterOptions() : Options("Cluster Options") {
+ addOptions()
+ ("cluster-name", optValue(name, "NAME"), "Name of cluster to join")
+ ("cluster-url", optValue(url,"URL"),
+ "URL of this broker, advertized to the cluster.\n"
+ "Defaults to a URL listing all the local IP addresses\n");
+ }
+
+ Url getUrl(uint16_t port) const {
+ if (url.empty()) return Url::getIpAddressesUrl(port);
+ return Url(url);
+ }
+};
+
+struct ClusterPlugin : public Plugin {
+
+ ClusterOptions options;
+ boost::optional<Cluster> cluster;
+
+ Options* getOptions() { return &options; }
+
+ void earlyInitialize(Plugin::Target&) {}
+
+ void initialize(Plugin::Target& target) {
+ broker::Broker* broker = dynamic_cast<broker::Broker*>(&target);
+ // Only provide to a Broker, and only if the --cluster config is set.
+ if (broker && !options.name.empty()) {
+ assert(!cluster); // A process can only belong to one cluster.
+ cluster = boost::in_place(options.name,
+ options.getUrl(broker->getPort()),
+ boost::ref(*broker));
+ broker->getPreviewSessionManager().add(cluster->getObserver());
+ }
+ }
+};
+
+static ClusterPlugin instance; // Static initialization.
+
+}} // namespace qpid::cluster
diff --git a/qpid/cpp/src/qpid/cluster/Cpg.cpp b/qpid/cpp/src/qpid/cluster/Cpg.cpp
new file mode 100644
index 0000000000..01d97d2a17
--- /dev/null
+++ b/qpid/cpp/src/qpid/cluster/Cpg.cpp
@@ -0,0 +1,176 @@
+/*
+ *
+ * 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/log/Statement.h"
+
+#include <vector>
+#include <limits>
+#include <iterator>
+
+#include <unistd.h>
+
+namespace qpid {
+namespace cluster {
+
+using namespace std;
+
+// Global vector of Cpg pointers by handle.
+// TODO aconway 2007-06-12: Replace this with cpg_get/set_context,
+// coming in in RHEL 5.1.
+class Cpg::Handles
+{
+ public:
+ void put(cpg_handle_t handle, Cpg::Handler* handler) {
+ sys::Mutex::ScopedLock l(lock);
+ uint32_t index=uint32_t(handle); // Lower 32 bits is an array index.
+ if (index >= handles.size())
+ handles.resize(index+1, 0);
+ handles[index] = handler;
+ }
+
+ Cpg::Handler* get(cpg_handle_t handle) {
+ sys::Mutex::ScopedLock l(lock);
+ uint32_t index=uint32_t(handle); // Lower 32 bits is an array index.
+ assert(index < handles.size());
+ assert(handles[index]);
+ return handles[index];
+ }
+
+ private:
+ sys::Mutex lock;
+ vector<Cpg::Handler*> handles;
+};
+
+Cpg::Handles Cpg::handles;
+
+// Global callback functions call per-object callbacks via handles vector.
+void Cpg::globalDeliver (
+ cpg_handle_t handle,
+ struct cpg_name *group,
+ uint32_t nodeid,
+ uint32_t pid,
+ void* msg,
+ int msg_len)
+{
+ Cpg::Handler* handler=handles.get(handle);
+ if (handler)
+ 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
+)
+{
+ Cpg::Handler* handler=handles.get(handle);
+ if (handler)
+ handler->configChange(handle, group, members, nMembers, left, nLeft, joined, nJoined);
+}
+
+Cpg::Cpg(Handler& h) : handler(h) {
+ cpg_callbacks_t callbacks = { &globalDeliver, &globalConfigChange };
+ check(cpg_initialize(&handle, &callbacks), "Cannot initialize CPG");
+ handles.put(handle, &handler);
+ QPID_LOG(debug, "Initialize CPG handle " << handle);
+}
+
+Cpg::~Cpg() {
+ try {
+ shutdown();
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Exception in Cpg destructor: " << e.what());
+ }
+}
+
+void Cpg::shutdown() {
+ QPID_LOG(debug, "Shutdown CPG handle " << handle);
+ if (handles.get(handle)) {
+ QPID_LOG(debug, "Finalize CPG handle " << handle);
+ handles.put(handle, 0);
+ check(cpg_finalize(handle), "Error in shutdown of CPG");
+ }
+}
+
+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";
+ 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. You may need to set your group ID to 'ais'";
+ 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();
+}
+
+ostream& operator<<(ostream& o, std::pair<cpg_address*,int> a) {
+ ostream_iterator<Cpg::Id> i(o, " ");
+ std::copy(a.first, a.first+a.second, i);
+ return o;
+}
+
+static int popbyte(uint32_t& n) {
+ uint8_t b=n&0xff;
+ n>>=8;
+ return b;
+}
+
+ostream& operator <<(ostream& out, const Cpg::Id& id) {
+ uint32_t node=id.nodeId();
+ out << popbyte(node);
+ for (int i = 0; i < 3; i++)
+ out << "." << popbyte(node);
+ return out << ":" << id.pid();
+}
+
+ostream& operator <<(ostream& out, const cpg_name& name) {
+ return out << string(name.value, name.length);
+}
+
+
+}} // namespace qpid::cluster
+
+
+
diff --git a/qpid/cpp/src/qpid/cluster/Cpg.h b/qpid/cpp/src/qpid/cluster/Cpg.h
new file mode 100644
index 0000000000..2a7ec459d3
--- /dev/null
+++ b/qpid/cpp/src/qpid/cluster/Cpg.h
@@ -0,0 +1,185 @@
+#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 <cassert>
+#include <string.h>
+
+extern "C" {
+#include <openais/cpg.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 Dispatchable {
+ public:
+ struct Exception : public ::qpid::Exception {
+ Exception(const std::string& msg) : ::qpid::Exception(msg) {}
+ };
+
+ struct Name : public cpg_name {
+ 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); }
+ };
+
+ struct Id {
+ uint64_t id;
+ Id(uint64_t n=0) : id(n) {}
+ Id(uint32_t nodeid, uint32_t pid) { id=(uint64_t(nodeid)<<32)+ pid; }
+ Id(const cpg_address& addr) : id(Id(addr.nodeid, addr.pid)) {}
+
+ operator uint64_t() const { return id; }
+ uint32_t nodeId() const { return id >> 32; }
+ pid_t pid() const { return id & 0xFFFF; }
+ };
+
+ 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. */
+ ~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) {
+ check(cpg_dispatch(handle,type), "Error in CPG dispatch");
+ }
+
+ void dispatchOne() { dispatch(CPG_DISPATCH_ONE); }
+ void dispatchAll() { dispatch(CPG_DISPATCH_ALL); }
+ void dispatchBlocking() { dispatch(CPG_DISPATCH_BLOCKING); }
+
+ void join(const Name& group) {
+ check(cpg_join(handle, const_cast<Name*>(&group)),cantJoinMsg(group));
+ };
+
+ void leave(const Name& group) {
+ check(cpg_leave(handle,const_cast<Name*>(&group)),cantLeaveMsg(group));
+ }
+
+ void mcast(const Name& group, const iovec* iov, int iovLen) {
+ check(cpg_mcast_joined(
+ handle, CPG_TYPE_AGREED, const_cast<iovec*>(iov), iovLen),
+ cantMcastMsg(group));
+ }
+
+ cpg_handle_t getHandle() const { return handle; }
+
+ private:
+ class Handles;
+ struct ClearHandleOnExit;
+ friend class Handles;
+ friend struct ClearHandleOnExit;
+
+ 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) {
+ // TODO aconway 2007-06-01: Logging and exceptions.
+ if (result != CPG_OK)
+ throw Exception(errorStr(result, msg));
+ }
+
+ 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*/
+ );
+
+ static Handles handles;
+ cpg_handle_t handle;
+ Handler& handler;
+};
+
+std::ostream& operator <<(std::ostream& out, const cpg_name& name);
+std::ostream& operator <<(std::ostream& out, const Cpg::Id& id);
+std::ostream& operator <<(std::ostream& out, const std::pair<cpg_address*,int> addresses);
+
+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/qpid/cpp/src/qpid/cluster/Dispatchable.h b/qpid/cpp/src/qpid/cluster/Dispatchable.h
new file mode 100644
index 0000000000..e7f0df4218
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/doxygen_mainpage.h b/qpid/cpp/src/qpid/doxygen_mainpage.h
new file mode 100644
index 0000000000..b354238cd0
--- /dev/null
+++ b/qpid/cpp/src/qpid/doxygen_mainpage.h
@@ -0,0 +1,45 @@
+// This header file is just for doxygen documentation purposes.
+
+/*!\mainpage Qpid C++ Developer Kit.
+ *
+ *\section intro_sec Introduction
+ *
+ * The <a href=http://incubator.apache.org/qpid/index.html>Qpid project</a> provides implementations of the <a href="http://amqp.org/">AMQP messaging specification</a> in several programming language.
+ *
+ * Qpidc provides APIs and libraries to implement AMQP
+ * clients in C++. Qpidc clients can interact with any compliant AMQP
+ * message broker. The Qpid project also provides an AMQP broker
+ * daemon called qpidd that you can use with your qpidc clients.
+ *
+ *\section install_sec Installation
+ *
+ * If you are installing from the source distribution
+ <pre>
+ > ./configure && make
+ > make install </pre>
+ * This will build and install the client development kit and the broker
+ * in standard places. Use
+ * <code>./configure --help</code> for more options.
+ *
+ * You can also install from RPMs with the <code>rpm -i</code> command.
+ * You will need
+ * - <code>qpidc</code> for core libraries.
+ * - <code>qpidc-devel</code> for header files and developer documentation.
+ * - <code>qpidd</code> for the broker daemon.
+ *
+ *\section getstart_sec Getting Started
+ *
+ * If you have installed in the standard places you should use
+ * these compile flags:
+ *
+ *<code> -I/usr/include/qpidc -I/usr/include/qpidc/framing -I/usr/include/qpidc/sys</code>
+ *
+ * and these link flags:
+ *
+ *<code> -lqpidcommon -lqpidclient</code>
+ *
+ * If you have installed somewhere else you should modify the flags
+ * appropriately.
+ *
+ * See the \ref clientapi "client API module" for more on the client API.
+ */
diff --git a/qpid/cpp/src/qpid/framing/AMQBody.cpp b/qpid/cpp/src/qpid/framing/AMQBody.cpp
new file mode 100644
index 0000000000..b3eeae0615
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/framing/AMQBody.h b/qpid/cpp/src/qpid/framing/AMQBody.h
new file mode 100644
index 0000000000..f3bf65470c
--- /dev/null
+++ b/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 size() 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/qpid/cpp/src/qpid/framing/AMQCommandControlBody.h b/qpid/cpp/src/qpid/framing/AMQCommandControlBody.h
new file mode 100644
index 0000000000..388fb48299
--- /dev/null
+++ b/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 size() 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/qpid/cpp/src/qpid/framing/AMQContentBody.cpp b/qpid/cpp/src/qpid/framing/AMQContentBody.cpp
new file mode 100644
index 0000000000..59f3619ef2
--- /dev/null
+++ b/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::size() 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 (" << size() << " bytes)";
+ out << " " << data.substr(0,16) << "...";
+}
diff --git a/qpid/cpp/src/qpid/framing/AMQContentBody.h b/qpid/cpp/src/qpid/framing/AMQContentBody.h
new file mode 100644
index 0000000000..5d530a1b9a
--- /dev/null
+++ b/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 size() 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/qpid/cpp/src/qpid/framing/AMQDataBlock.h b/qpid/cpp/src/qpid/framing/AMQDataBlock.h
new file mode 100644
index 0000000000..9b6fdfd966
--- /dev/null
+++ b/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 size() const = 0;
+};
+
+}
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/framing/AMQFrame.cpp b/qpid/cpp/src/qpid/framing/AMQFrame.cpp
new file mode 100644
index 0000000000..eeb658600d
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/AMQFrame.cpp
@@ -0,0 +1,123 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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); }
+
+// This is now misleadingly named as it is not the frame size as
+// defined in the spec (as it also includes the end marker)
+uint32_t AMQFrame::size() const {
+ return frameOverhead() + body->size();
+}
+
+uint32_t AMQFrame::frameOverhead() {
+ return 12 /*frame header*/ + 1/*0xCE*/;
+}
+
+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(size() - 1); // Don't include end marker (it's not part of the frame itself)
+ buffer.putOctet(0);
+ buffer.putOctet(0x0f & track);
+ buffer.putShort(channel);
+ buffer.putLong(0);
+ body->encode(buffer);
+ buffer.putOctet(0xCE);
+}
+
+bool AMQFrame::decode(Buffer& buffer)
+{
+ if(buffer.available() < frameOverhead() - 1)
+ return false;
+ buffer.record();
+
+ uint8_t flags = buffer.getOctet();
+ uint8_t framing_version = (flags & 0xc0) >> 6;
+ if (framing_version != 0)
+ throw SyntaxErrorException(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()-1)
+ throw SyntaxErrorException(QPID_MSG("Frame size too small"));
+ 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 SyntaxErrorException(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 + 1 - frameOverhead();
+ if (buffer.available() < body_size+1u){
+ buffer.restore();
+ return false;
+ }
+ body = new BodyHolder();
+ body->decode(type,buffer, body_size);
+ uint8_t end = buffer.getOctet();
+ if (end != 0xCE)
+ throw SyntaxErrorException(QPID_MSG("Frame end not found"));
+ 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/qpid/cpp/src/qpid/framing/AMQFrame.h b/qpid/cpp/src/qpid/framing/AMQFrame.h
new file mode 100644
index 0000000000..649a65bce4
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/AMQFrame.h
@@ -0,0 +1,112 @@
+#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 size() const;
+
+ 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 uint32_t frameOverhead();
+
+ 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/qpid/cpp/src/qpid/framing/AMQHeaderBody.cpp b/qpid/cpp/src/qpid/framing/AMQHeaderBody.cpp
new file mode 100644
index 0000000000..724c288705
--- /dev/null
+++ b/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::size() const {
+ return properties.size();
+}
+
+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 (" << size() << " bytes)";
+ out << "; properties={";
+ properties.print(out);
+ out << "}";
+}
+
+void qpid::framing::AMQHeaderBody::accept(AMQBodyConstVisitor& v) const {
+ v.visit(*this);
+}
diff --git a/qpid/cpp/src/qpid/framing/AMQHeaderBody.h b/qpid/cpp/src/qpid/framing/AMQHeaderBody.h
new file mode 100644
index 0000000000..8a3a92936e
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/AMQHeaderBody.h
@@ -0,0 +1,113 @@
+#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 "qpid/framing/DeliveryProperties010.h"
+#include "qpid/framing/MessageProperties010.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 size() const {
+ const boost::optional<T>& p=this->OptProps<T>::props;
+ return (p ? p->size() : 0) + Base::size();
+ }
+ 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 size() 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< PropSet<PropSet<Empty, DeliveryProperties>,
+ MessageProperties>,
+ DeliveryProperties010>,
+ MessageProperties010> Properties;
+
+ Properties properties;
+
+public:
+
+ inline uint8_t type() const { return HEADER_BODY; }
+
+ uint32_t size() 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/qpid/cpp/src/qpid/framing/AMQHeartbeatBody.cpp b/qpid/cpp/src/qpid/framing/AMQHeartbeatBody.cpp
new file mode 100644
index 0000000000..140ce2e794
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/framing/AMQHeartbeatBody.h b/qpid/cpp/src/qpid/framing/AMQHeartbeatBody.h
new file mode 100644
index 0000000000..a2701c3398
--- /dev/null
+++ b/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 size() 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/qpid/cpp/src/qpid/framing/AMQMethodBody.cpp b/qpid/cpp/src/qpid/framing/AMQMethodBody.cpp
new file mode 100644
index 0000000000..924d906d43
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/framing/AMQMethodBody.h b/qpid/cpp/src/qpid/framing/AMQMethodBody.h
new file mode 100644
index 0000000000..da28ee3aa9
--- /dev/null
+++ b/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 size() 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/qpid/cpp/src/qpid/framing/AMQP_HighestVersion.h b/qpid/cpp/src/qpid/framing/AMQP_HighestVersion.h
new file mode 100644
index 0000000000..b15e14d6f6
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/AMQP_HighestVersion.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.
+ *
+ */
+
+/*
+ * 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(99, 0);
+//static ProtocolVersion highestProtocolVersion(0, 10);
+
+} /* namespace framing */
+} /* namespace qpid */
+
+#endif
diff --git a/qpid/cpp/src/qpid/framing/AccumulatedAck.cpp b/qpid/cpp/src/qpid/framing/AccumulatedAck.cpp
new file mode 100644
index 0000000000..2d3ecf3f6a
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/framing/AccumulatedAck.h b/qpid/cpp/src/qpid/framing/AccumulatedAck.h
new file mode 100644
index 0000000000..a635d2ea04
--- /dev/null
+++ b/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 acked messages (by delivery
+ * tag).
+ */
+ class AccumulatedAck {
+ public:
+ /**
+ * Everything up to this value has been acked.
+ */
+ SequenceNumber mark;
+ /**
+ * List of individually acked 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/qpid/cpp/src/qpid/framing/Array.cpp b/qpid/cpp/src/qpid/framing/Array.cpp
new file mode 100644
index 0000000000..71281c7a52
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/Array.cpp
@@ -0,0 +1,127 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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() : typeOctet(0xF0/*void*/) {}
+
+Array::Array(uint8_t type) : typeOctet(type) {}
+
+Array::Array(const std::vector<std::string>& in)
+{
+ typeOctet = 0xA4;
+ for (std::vector<std::string>::const_iterator i = in.begin(); i != in.end(); ++i) {
+ ValuePtr value(new StringValue(*i));
+ values.push_back(value);
+ }
+}
+
+
+uint32_t Array::size() 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().size();
+ }
+ return len;
+}
+
+int Array::count() const {
+ return values.size();
+}
+
+std::ostream& operator<<(std::ostream& out, const Array& t) {
+ out << "{";
+ for(Array::ValueVector::const_iterator i = t.values.begin(); i != t.values.end(); ++i) {
+ if (i != t.values.begin()) out << ", ";
+ out << *(i->get());
+ }
+ return out << "}";
+}
+
+void Array::encode(Buffer& buffer) const{
+ buffer.putLong(size() - 4);//size added only when array is a top-level type
+ buffer.putOctet(typeOctet);
+ 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 SyntaxErrorException(QPID_MSG("Not enough data for array, expected "
+ << size << " bytes but only " << available << " available"));
+ }
+ if (size) {
+ typeOctet = buffer.getOctet();
+ uint32_t count = buffer.getLong();
+
+ FieldValue dummy;
+ dummy.setType(typeOctet);
+ available = buffer.available();
+ if (available < count * dummy.getData().size()) {
+ throw SyntaxErrorException(QPID_MSG("Not enough data for array, expected "
+ << count << " items of " << dummy.getData().size()
+ << " bytes each but only " << available << " bytes available"));
+ }
+
+ for (uint32_t i = 0; i < count; i++) {
+ ValuePtr value(new FieldValue);
+ value->setType(typeOctet);
+ value->getData().decode(buffer);
+ values.push_back(ValuePtr(value));
+ }
+ }
+}
+
+
+bool Array::operator==(const Array& x) const {
+ if (typeOctet != x.typeOctet) 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::add(ValuePtr value)
+{
+ if (typeOctet != value->getType()) {
+ throw SyntaxErrorException(QPID_MSG("Wrong type of value, expected " << typeOctet));
+ }
+ values.push_back(value);
+}
+
+
+}
+}
diff --git a/qpid/cpp/src/qpid/framing/Array.h b/qpid/cpp/src/qpid/framing/Array.h
new file mode 100644
index 0000000000..1367a023f2
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/Array.h
@@ -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 <iostream>
+#include <vector>
+#include <boost/shared_ptr.hpp>
+#include <map>
+#include "amqp_types.h"
+#include "FieldValue.h"
+
+#ifndef _Array_
+#define _Array_
+
+namespace qpid {
+namespace framing {
+
+class Buffer;
+
+class Array
+{
+ public:
+ typedef boost::shared_ptr<FieldValue> ValuePtr;
+ typedef std::vector<ValuePtr> ValueVector;
+
+ uint32_t size() const;
+ void encode(Buffer& buffer) const;
+ void decode(Buffer& buffer);
+
+ int count() const;
+ bool operator==(const Array& other) const;
+
+ Array();
+ Array(uint8_t type);
+ //creates a longstr array
+ Array(const std::vector<std::string>& in);
+
+ void add(ValuePtr value);
+
+ template <class T>
+ void collect(std::vector<T>& out)
+ {
+ for (ValueVector::const_iterator i = values.begin(); i != values.end(); ++i) {
+ out.push_back((*i)->get<T>());
+ }
+ }
+
+ private:
+ uint8_t typeOctet;
+ ValueVector values;
+
+ ValueVector::const_iterator begin() const { return values.begin(); }
+ ValueVector::const_iterator end() const { return values.end(); }
+
+ friend std::ostream& operator<<(std::ostream& out, const Array& body);
+};
+
+}
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/framing/Blob.cpp b/qpid/cpp/src/qpid/framing/Blob.cpp
new file mode 100644
index 0000000000..388d4b64ef
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/framing/Blob.h b/qpid/cpp/src/qpid/framing/Blob.h
new file mode 100644
index 0000000000..cf81f693b0
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/Blob.h
@@ -0,0 +1,193 @@
+#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 <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 boost. */
+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>(); }
+
+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(). Blob
+ * ensures proper construction and destruction of its contents,
+ * and proper copying between Blobs, but nothing else.
+ *
+ * In particular the user must ensure 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 object that can be
+ * safely 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());
+ b.copy(this->store.address(), b.store.address());
+ copy = b.copy;
+ destroy = b.destroy;
+ basePtr = reinterpret_cast<BaseType*>(
+ ((char*)this)+ ((char*)(b.basePtr) - (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 objecct 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/qpid/cpp/src/qpid/framing/BodyHandler.cpp b/qpid/cpp/src/qpid/framing/BodyHandler.cpp
new file mode 100644
index 0000000000..fb84be7cd6
--- /dev/null
+++ b/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 SyntaxErrorException(
+ QPID_MSG("Invalid frame type " << body->type()));
+ }
+}
+
diff --git a/qpid/cpp/src/qpid/framing/BodyHandler.h b/qpid/cpp/src/qpid/framing/BodyHandler.h
new file mode 100644
index 0000000000..9ded737195
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/framing/BodyHolder.cpp b/qpid/cpp/src/qpid/framing/BodyHolder.cpp
new file mode 100644
index 0000000000..de971b5b28
--- /dev/null
+++ b/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 SyntaxErrorException(QPID_MSG("Invalid frame type " << type));
+ }
+ get()->decode(buffer, size);
+}
+
+uint32_t BodyHolder::size() const {
+ const AMQMethodBody* method=getMethod();
+ if (method)
+ return sizeof(ClassId)+sizeof(MethodId)+method->size();
+ else
+ return get()->size();
+}
+
+}} // namespace qpid::framing
+
diff --git a/qpid/cpp/src/qpid/framing/BodyHolder.h b/qpid/cpp/src/qpid/framing/BodyHolder.h
new file mode 100644
index 0000000000..65029e5675
--- /dev/null
+++ b/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 size() 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/qpid/cpp/src/qpid/framing/Buffer.cpp b/qpid/cpp/src/qpid/framing/Buffer.cpp
new file mode 100644
index 0000000000..69168d462a
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/Buffer.cpp
@@ -0,0 +1,276 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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 "FramingContent.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;
+}
+
+void Buffer::putShort(uint16_t i){
+ uint16_t b = i;
+ data[position++] = (uint8_t) (0xFF & (b >> 8));
+ data[position++] = (uint8_t) (0xFF & b);
+}
+
+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);
+}
+
+void Buffer::putLongLong(uint64_t i){
+ uint32_t hi = i >> 32;
+ uint32_t lo = i;
+ putLong(hi);
+ putLong(lo);
+}
+
+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(){
+ return (uint8_t) data[position++];
+}
+
+uint16_t Buffer::getShort(){
+ uint16_t hi = (unsigned char) data[position++];
+ hi = hi << 8;
+ hi |= (unsigned char) data[position++];
+ 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++];
+ 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;
+}
+
+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){
+ uint8_t len = s.length();
+ putOctet(len);
+ s.copy(data + position, len);
+ position += len;
+}
+
+void Buffer::putMediumString(const string& s){
+ uint16_t len = s.length();
+ 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/qpid/cpp/src/qpid/framing/Buffer.h b/qpid/cpp/src/qpid/framing/Buffer.h
new file mode 100644
index 0000000000..94cc2d320f
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/Buffer.h
@@ -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 "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 {};
+
+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); }
+
+ void putOctet(uint8_t i);
+ void putShort(uint16_t i);
+ void putLong(uint32_t i);
+ void putLongLong(uint64_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();
+ 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/qpid/cpp/src/qpid/framing/ChannelHandler.h b/qpid/cpp/src/qpid/framing/ChannelHandler.h
new file mode 100644
index 0000000000..69aaeac492
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/framing/FieldTable.cpp b/qpid/cpp/src/qpid/framing/FieldTable.cpp
new file mode 100644
index 0000000000..089bc5d4a5
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/FieldTable.cpp
@@ -0,0 +1,165 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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 "Buffer.h"
+#include "FieldValue.h"
+#include "qpid/Exception.h"
+#include "qpid/framing/reply_exceptions.h"
+#include <assert.h>
+
+namespace qpid {
+namespace framing {
+
+FieldTable::~FieldTable() {}
+
+uint32_t FieldTable::size() const {
+ uint32_t len(4);
+ 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)->size();
+ }
+ 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 StringValue(value));
+}
+
+void FieldTable::setInt(const std::string& name, int value){
+ values[name] = ValuePtr(new IntegerValue(value));
+}
+
+void FieldTable::setTimestamp(const std::string& name, uint64_t value){
+ values[name] = ValuePtr(new TimeValue(value));
+}
+
+void FieldTable::setTable(const std::string& name, const FieldTable& value){
+ values[name] = ValuePtr(new FieldTableValue(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::getString(const std::string& name) const {
+ return getValue<std::string>(get(name));
+}
+
+int FieldTable::getInt(const std::string& name) const {
+ return getValue<int>(get(name));
+}
+
+//uint64_t FieldTable::getTimestamp(const std::string& name) const {
+// return getValue<uint64_t>(name);
+//}
+//
+//void FieldTable::getTable(const std::string& name, FieldTable& value) const {
+// value = getValue<FieldTable>(name);
+//}
+
+void FieldTable::encode(Buffer& buffer) const{
+ buffer.putLong(size() - 4);
+ 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();
+ uint32_t available = buffer.available();
+ if (available < len)
+ throw SyntaxErrorException(QPID_MSG("Not enough data for field table."));
+ uint32_t leftover = available - len;
+ while(buffer.available() > leftover){
+ 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)
+//{
+// values.erase(values.find(name));
+//}
+
+}
+}
diff --git a/qpid/cpp/src/qpid/framing/FieldTable.h b/qpid/cpp/src/qpid/framing/FieldTable.h
new file mode 100644
index 0000000000..707496a861
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/FieldTable.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 <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 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;
+
+ ~FieldTable();
+ uint32_t size() 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;
+
+ void setString(const std::string& name, const std::string& value);
+ void setInt(const std::string& name, int value);
+ void setTimestamp(const std::string& name, uint64_t value);
+ void setTable(const std::string& name, const FieldTable& value);
+ //void setDecimal(string& name, xxx& value);
+
+ std::string getString(const std::string& name) const;
+ int getInt(const std::string& name) const;
+// uint64_t getTimestamp(const std::string& name) const;
+// void getTable(const std::string& name, FieldTable& value) const;
+// //void 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); }
+
+ 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/qpid/cpp/src/qpid/framing/FieldValue.cpp b/qpid/cpp/src/qpid/framing/FieldValue.cpp
new file mode 100644
index 0000000000..cbda061209
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/FieldValue.cpp
@@ -0,0 +1,136 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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 "Buffer.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;
+
+ 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 SyntaxErrorException(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;
+}
+
+StringValue::StringValue(const std::string& v) :
+ FieldValue(
+ 0xA4,
+ new VariableWidthValue<4>(
+ 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())))
+{}
+
+IntegerValue::IntegerValue(int v) :
+ FieldValue(0x21, new FixedWidthValue<4>(v))
+{
+}
+
+TimeValue::TimeValue(uint64_t v) :
+ FieldValue(0x32, new FixedWidthValue<8>(v))
+{
+}
+
+FieldTableValue::FieldTableValue(const FieldTable&) : FieldValue()
+{
+}
+
+}}
diff --git a/qpid/cpp/src/qpid/framing/FieldValue.h b/qpid/cpp/src/qpid/framing/FieldValue.h
new file mode 100644
index 0000000000..272670d102
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/FieldValue.h
@@ -0,0 +1,235 @@
+#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 "Buffer.h"
+#include "amqp_types.h"
+
+#include "assert.h"
+
+#include <iostream>
+#include <memory>
+#include <vector>
+
+namespace qpid {
+namespace framing {
+
+/**
+ * Exception that is 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 size() 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 size() const { return 1 + data->size(); };
+ 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 { out << "(0x" << std::hex << int(typeOctet) << ")"; data->print(out); }
+
+ 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<std::string>() const { return data->convertsToString(); }
+
+template <>
+inline int FieldValue::get<int>() 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(uint64_t v)
+ {
+ for (int i = width; i > 0; --i) {
+ octets[i-1] = (uint8_t) (0xFF & v); v >>= 8;
+ }
+ octets[0] = (uint8_t) (0xFF & v);
+ }
+
+ uint32_t size() 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;
+ }
+
+ void print(std::ostream& o) const { o << "F" << width << ":"; };
+};
+
+template <>
+class FixedWidthValue<0> : public FieldValue::Data {
+ public:
+ // Implicit default constructor is fine
+ uint32_t size() 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 size() const { return lenwidth + octets.size(); }
+ void encode(Buffer& buffer) {
+ buffer.putUInt<lenwidth>(octets.size());
+ buffer.putRawData(&octets[0], octets.size());
+ };
+ void decode(Buffer& buffer) {
+ uint32_t len = buffer.getUInt<lenwidth>();
+ octets.resize(len);
+ 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() << ":"; };
+};
+
+/*
+ * Basic string value encodes as iso-8859-15 with 32 bit length
+ */
+class StringValue : public FieldValue {
+ public:
+ StringValue(const std::string& v);
+};
+
+class Str16Value : public FieldValue {
+ public:
+ Str16Value(const std::string& v);
+};
+
+/*
+ * 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 FieldTableValue : public FieldValue {
+ public:
+ FieldTableValue(const FieldTable&);
+};
+
+}} // qpid::framing
+
+#endif
diff --git a/qpid/cpp/src/qpid/framing/FrameDefaultVisitor.h b/qpid/cpp/src/qpid/framing/FrameDefaultVisitor.h
new file mode 100644
index 0000000000..07e1d6d997
--- /dev/null
+++ b/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, combines
+ * AMQBodyConstVisitor and MethodBodyDefaultVisitor.
+ *
+ * Derived classes may 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/qpid/cpp/src/qpid/framing/FrameHandler.h b/qpid/cpp/src/qpid/framing/FrameHandler.h
new file mode 100644
index 0000000000..457968c35e
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/framing/FrameSet.cpp b/qpid/cpp/src/qpid/framing/FrameSet.cpp
new file mode 100644
index 0000000000..e6f15f2c4e
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/FrameSet.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 "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) {parts.reserve(4);}
+
+void FrameSet::append(const AMQFrame& part)
+{
+ parts.push_back(part);
+}
+
+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
+{
+ SumBodySize sum;
+ map_if(sum, TypeFilter<CONTENT_BODY>());
+ return sum.getSize();
+}
+
+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/qpid/cpp/src/qpid/framing/FrameSet.h b/qpid/cpp/src/qpid/framing/FrameSet.h
new file mode 100644
index 0000000000..454d292d9d
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/FrameSet.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.
+ *
+ */
+#include <string>
+#include <vector>
+#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 std::vector<AMQFrame> Frames;
+ const SequenceNumber id;
+ Frames parts;
+
+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(remove_if(parts.begin(), parts.end(), predicate), parts.end());
+ }
+
+ template <class F> void map(F& functor) {
+ for_each(parts.begin(), parts.end(), functor);
+ }
+
+ template <class F> void map(F& functor) const {
+ 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/qpid/cpp/src/qpid/framing/FramingContent.cpp b/qpid/cpp/src/qpid/framing/FramingContent.cpp
new file mode 100644
index 0000000000..cd134b0e89
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/FramingContent.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 "Buffer.h"
+#include "FramingContent.h"
+#include "qpid/Exception.h"
+#include "qpid/framing/reply_exceptions.h"
+
+namespace qpid {
+namespace framing {
+
+Content::Content() : discriminator(0) {}
+
+Content::Content(uint8_t _discriminator, const string& _value): discriminator(_discriminator), value(_value) {
+ validate();
+}
+
+void Content::validate() {
+ if (discriminator == REFERENCE) {
+ if(value.empty()) {
+ throw InvalidArgumentException(
+ QPID_MSG("Reference cannot be empty"));
+ }
+ }else if (discriminator != INLINE) {
+ throw SyntaxErrorException(
+ QPID_MSG("Invalid discriminator: " << discriminator));
+ }
+}
+
+Content::~Content() {}
+
+void Content::encode(Buffer& buffer) const {
+ buffer.putOctet(discriminator);
+ buffer.putLongString(value);
+}
+
+void Content::decode(Buffer& buffer) {
+ discriminator = buffer.getOctet();
+ buffer.getLongString(value);
+ validate();
+}
+
+size_t Content::size() const {
+ return 1/*discriminator*/ + 4/*for recording size of long string*/ + value.size();
+}
+
+std::ostream& operator<<(std::ostream& out, const Content& content) {
+ if (content.discriminator == REFERENCE) {
+ out << "{REF:" << content.value << "}";
+ } else if (content.discriminator == INLINE) {
+ out << "{INLINE:" << content.value.size() << " bytes}";
+ }
+ return out;
+}
+
+}} // namespace framing::qpid
diff --git a/qpid/cpp/src/qpid/framing/FramingContent.h b/qpid/cpp/src/qpid/framing/FramingContent.h
new file mode 100644
index 0000000000..9315a7716f
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/FramingContent.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 _framing_FramingContent_h
+#define _framing_FramingContent_h
+
+#include <ostream>
+
+namespace qpid {
+namespace framing {
+
+class Buffer;
+
+enum discriminator_types { INLINE = 0, REFERENCE = 1 };
+
+/**
+ * A representation of the AMQP 'content' data type (used for message
+ * bodies) which can hold inline data or a reference.
+ */
+class Content
+{
+ uint8_t discriminator;
+ string value;
+
+ void validate();
+
+ public:
+ Content();
+ Content(uint8_t _discriminator, const string& _value);
+ ~Content();
+
+ void encode(Buffer& buffer) const;
+ void decode(Buffer& buffer);
+ size_t size() const;
+ bool isInline() const { return discriminator == INLINE; }
+ bool isReference() const { return discriminator == REFERENCE; }
+ const string& getValue() const { return value; }
+ void setValue(const string& newValue) { value = newValue; }
+
+ friend std::ostream& operator<<(std::ostream&, const Content&);
+};
+
+}} // namespace qpid::framing
+
+
+#endif /*!_framing_FramingContent_h*/
diff --git a/qpid/cpp/src/qpid/framing/Handler.h b/qpid/cpp/src/qpid/framing/Handler.h
new file mode 100644
index 0000000000..fbf3c0b7ca
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/Handler.h
@@ -0,0 +1,122 @@
+#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 {
+
+/** Generic handler that can be linked into chains. */
+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;
+
+ /** A Chain is a handler that forwards to a modifiable
+ * linked list of handlers.
+ */
+ struct Chain : public Handler<T> {
+ Chain(Handler<T>* first=0) : Handler(first) {}
+ void operator=(Handler<T>* h) { next = h; }
+ void handle(T t) { next->handle(t); }
+ // TODO aconway 2007-08-29: chain modifier ops here.
+ };
+
+ /** In/out pair of handler chains. */
+ struct Chains {
+ Chains(Handler<T>* in_=0, Handler<T>* out_=0) : in(in_), out(out_) {}
+ void reset(Handler<T>* in_=0, Handler<T>* out_=0) { in = in_; out = out_; }
+ Chain in;
+ Chain out;
+ };
+
+ /** 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, compatible with Chains */
+ 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.
+ * Public interface is Handler<T>::Chains pair, but implementation
+ * 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/qpid/cpp/src/qpid/framing/HeaderProperties.h b/qpid/cpp/src/qpid/framing/HeaderProperties.h
new file mode 100644
index 0000000000..0c805922e8
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/HeaderProperties.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 "Buffer.h"
+
+#ifndef _HeaderProperties_
+#define _HeaderProperties_
+
+namespace qpid {
+namespace framing {
+
+ enum header_classes{BASIC = 60};
+
+ class HeaderProperties
+ {
+
+ public:
+ inline virtual ~HeaderProperties(){}
+ virtual uint8_t classId() const = 0;
+ virtual uint32_t size() const = 0;
+ virtual void encode(Buffer& buffer) const = 0;
+ virtual void decode(Buffer& buffer, uint32_t size) = 0;
+ };
+}
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/framing/InitiationHandler.cpp b/qpid/cpp/src/qpid/framing/InitiationHandler.cpp
new file mode 100644
index 0000000000..eceeaf4abc
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/framing/InitiationHandler.h b/qpid/cpp/src/qpid/framing/InitiationHandler.h
new file mode 100644
index 0000000000..16a6b502e8
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/framing/InputHandler.h b/qpid/cpp/src/qpid/framing/InputHandler.h
new file mode 100644
index 0000000000..3a6d786a24
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/framing/Invoker.h b/qpid/cpp/src/qpid/framing/Invoker.h
new file mode 100644
index 0000000000..6c2b972c13
--- /dev/null
+++ b/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 on 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 on 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/qpid/cpp/src/qpid/framing/MethodContent.h b/qpid/cpp/src/qpid/framing/MethodContent.h
new file mode 100644
index 0000000000..737c0d6b7b
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/framing/ModelMethod.h b/qpid/cpp/src/qpid/framing/ModelMethod.h
new file mode 100644
index 0000000000..07600aadca
--- /dev/null
+++ b/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/ExecutionHeader.h"
+
+namespace qpid {
+namespace framing {
+
+
+class ModelMethod : public AMQMethodBody
+{
+ mutable ExecutionHeader 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.size(); }
+ virtual bool isSync() const { return header.getSync(); }
+ virtual void setSync(bool on) const { header.setSync(on); }
+ ExecutionHeader& getHeader() { return header; }
+ const ExecutionHeader& getHeader() const { return header; }
+};
+
+
+}} // namespace qpid::framing
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/framing/OutputHandler.h b/qpid/cpp/src/qpid/framing/OutputHandler.h
new file mode 100644
index 0000000000..6f4b27fb72
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/framing/ProtocolInitiation.cpp b/qpid/cpp/src/qpid/framing/ProtocolInitiation.cpp
new file mode 100644
index 0000000000..50617de017
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/framing/ProtocolInitiation.h b/qpid/cpp/src/qpid/framing/ProtocolInitiation.h
new file mode 100644
index 0000000000..43e32da4cf
--- /dev/null
+++ b/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 size() 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/qpid/cpp/src/qpid/framing/ProtocolVersion.cpp b/qpid/cpp/src/qpid/framing/ProtocolVersion.cpp
new file mode 100644
index 0000000000..7a96bfa925
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/framing/ProtocolVersion.h b/qpid/cpp/src/qpid/framing/ProtocolVersion.h
new file mode 100644
index 0000000000..a2a755397b
--- /dev/null
+++ b/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:
+ 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/qpid/cpp/src/qpid/framing/Proxy.cpp b/qpid/cpp/src/qpid/framing/Proxy.cpp
new file mode 100644
index 0000000000..b47060028f
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/Proxy.cpp
@@ -0,0 +1,37 @@
+/*
+ *
+ * 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() {}
+
+void Proxy::send(const AMQBody& b) {
+ AMQFrame f(b);
+ out.handle(f);
+}
+
+
+ProtocolVersion Proxy::getVersion() const {
+ return ProtocolVersion();
+}
+
+}} // namespace qpid::framing
diff --git a/qpid/cpp/src/qpid/framing/Proxy.h b/qpid/cpp/src/qpid/framing/Proxy.h
new file mode 100644
index 0000000000..86b99a83b0
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/Proxy.h
@@ -0,0 +1,52 @@
+#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) : out(h) {}
+ virtual ~Proxy();
+
+ void send(const AMQBody&);
+
+ ProtocolVersion getVersion() const;
+ FrameHandler& getHandler() { return out; }
+
+ protected:
+ FrameHandler& out;
+};
+
+}} // namespace qpid::framing
+
+
+
+#endif /*!_framing_Proxy_h*/
diff --git a/qpid/cpp/src/qpid/framing/SendContent.cpp b/qpid/cpp/src/qpid/framing/SendContent.cpp
new file mode 100644
index 0000000000..a62e4eeb72
--- /dev/null
+++ b/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->size() > maxContentSize) {
+ uint32_t offset = 0;
+ for (int chunk = body->size() / maxContentSize; chunk > 0; chunk--) {
+ sendFragment(*body, offset, maxContentSize, first && offset == 0, last && offset + maxContentSize == body->size());
+ offset += maxContentSize;
+ }
+ uint32_t remainder = body->size() % 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/qpid/cpp/src/qpid/framing/SendContent.h b/qpid/cpp/src/qpid/framing/SendContent.h
new file mode 100644
index 0000000000..dcd5202b3e
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/framing/SequenceNumber.cpp b/qpid/cpp/src/qpid/framing/SequenceNumber.cpp
new file mode 100644
index 0000000000..1b62d296c6
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/SequenceNumber.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 "SequenceNumber.h"
+
+using qpid::framing::SequenceNumber;
+
+SequenceNumber::SequenceNumber() : value(0 - 1) {}
+
+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;
+}
+
+namespace qpid {
+namespace framing {
+
+int32_t operator-(const SequenceNumber& a, const SequenceNumber& b)
+{
+ int32_t result = a.value - b.value;
+ return result;
+}
+
+}}
diff --git a/qpid/cpp/src/qpid/framing/SequenceNumber.h b/qpid/cpp/src/qpid/framing/SequenceNumber.h
new file mode 100644
index 0000000000..0ed591b804
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/SequenceNumber.h
@@ -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.
+ *
+ */
+#ifndef _framing_SequenceNumber_h
+#define _framing_SequenceNumber_h
+
+#include "amqp_types.h"
+
+namespace qpid {
+namespace framing {
+
+/**
+ * 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);
+
+ template <class S> void serialize(S& s) { s(value); }
+};
+
+struct Window
+{
+ SequenceNumber hwm;
+ SequenceNumber lwm;
+};
+
+}} // namespace qpid::framing
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/framing/SequenceNumberSet.cpp b/qpid/cpp/src/qpid/framing/SequenceNumberSet.cpp
new file mode 100644
index 0000000000..afab9033e5
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/framing/SequenceNumberSet.h b/qpid/cpp/src/qpid/framing/SequenceNumberSet.h
new file mode 100644
index 0000000000..666307f9d9
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/framing/SequenceSet.cpp b/qpid/cpp/src/qpid/framing/SequenceSet.cpp
new file mode 100644
index 0000000000..1858467de6
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/SequenceSet.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 "SequenceSet.h"
+
+using namespace qpid::framing;
+using std::max;
+using std::min;
+
+namespace {
+//each range contains 2 numbers, 4 bytes each
+uint16_t RANGE_SIZE = 2 * 4;
+}
+
+void SequenceSet::encode(Buffer& buffer) const
+{
+ buffer.putShort(ranges.size() * RANGE_SIZE);
+ for (Ranges::const_iterator i = ranges.begin(); i != ranges.end(); i++) {
+ i->encode(buffer);
+ }
+}
+
+void SequenceSet::decode(Buffer& buffer)
+{
+ uint16_t size = buffer.getShort();
+ uint16_t count = size / RANGE_SIZE;//number of ranges
+ if (size % RANGE_SIZE) throw FrameErrorException(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::size() const
+{
+ return 2 /*size field*/ + (ranges.size() * RANGE_SIZE);
+}
+
+bool SequenceSet::contains(const SequenceNumber& point) const
+{
+ for (Ranges::const_iterator i = ranges.begin(); i != ranges.end(); i++) {
+ if (i->contains(point)) return true;
+ }
+ return false;
+}
+
+void SequenceSet::add(const SequenceNumber& s)
+{
+ add(s, s);
+}
+
+void SequenceSet::add(const SequenceNumber& start, const SequenceNumber& end)
+{
+ if (start > end) {
+ add(end, start);
+ } else {
+ Range r(start, end);
+ Ranges::iterator merged = ranges.end();
+ Ranges::iterator i = ranges.begin();
+ while (i != ranges.end() && merged == ranges.end() && i->start < start) {
+ if (i->merge(r)) merged = i;
+ i++;
+ }
+ if (merged == ranges.end()) {
+ i = merged = ranges.insert(i, r);
+ i++;
+ }
+ while (i != ranges.end() && merged->merge(*i)) {
+ i = ranges.erase(i);
+ }
+ }
+}
+
+void SequenceSet::add(const SequenceSet& set)
+{
+ for (Ranges::const_iterator i = set.ranges.begin(); i != set.ranges.end(); i++) {
+ add(i->start, i->end);
+ }
+}
+
+void SequenceSet::remove(const SequenceSet& set)
+{
+ for (Ranges::const_iterator i = set.ranges.begin(); i != set.ranges.end(); i++) {
+ remove(i->start, i->end);
+ }
+}
+
+void SequenceSet::remove(const SequenceNumber& start, const SequenceNumber& end)
+{
+ if (start > end) {
+ remove(end, start);
+ } else {
+ Ranges::iterator i = ranges.begin();
+ while (i != ranges.end() && i->start < start) {
+ if (start <= i->end) {
+ if (end > i->end) {
+ //i.e. start is within the range pointed to by i, but end is not
+ i->end = (uint32_t)start - 1;
+ } else {
+ //whole of range to be deleted is contained within that pointed to be i
+ if (end == i->end) {
+ //just shrink range pointed to by i
+ i->end = (uint32_t)start - 1;
+ } else {
+ //need to split the range pointed to by i
+ Range r(i->start, (uint32_t)start - 1);
+ i->start = end + 1;
+ ranges.insert(i, r);
+ }
+ return;//no need to go any further
+ }
+ }
+ i++;
+ }
+ Ranges::iterator j = i;
+ while (j != ranges.end() && j->end < end) {
+ j++;
+ }
+ if (j->start <= end){
+ j->start = end + 1;
+ }
+ ranges.erase(i, j);
+ }
+}
+
+void SequenceSet::remove(const SequenceNumber& s)
+{
+ for (Ranges::iterator i = ranges.begin(); i != ranges.end() && s >= i->start; i++) {
+ if (i->start == s) {
+ if (i->start == i->end) {
+ ranges.erase(i);
+ } else {
+ ++(i->start);
+ }
+ } else if (i->end == s) {
+ --(i->end);
+ } else if (i->contains(s)) {
+ //need to split range pointed to by i
+ Range r(i->start, (uint32_t)s - 1);
+ i->start = s + 1;
+ ranges.insert(i, r);
+ }
+ }
+}
+
+bool SequenceSet::empty() const
+{
+ return ranges.empty();
+}
+
+void SequenceSet::clear()
+{
+ return ranges.clear();
+}
+
+bool SequenceSet::Range::contains(SequenceNumber i) const
+{
+ return i >= start && i <= end;
+}
+
+bool SequenceSet::Range::intersects(const Range& r) const
+{
+ return r.contains(start) || r.contains(end) || contains(r.start) || contains(r.end);
+}
+
+bool SequenceSet::Range::merge(const Range& r)
+{
+ if (intersects(r) || mergeable(r.end) || r.mergeable(end)) {
+ start = min(start, r.start);
+ end = max(end, r.end);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool SequenceSet::Range::mergeable(const SequenceNumber& s) const
+{
+ if (contains(s) || start - s == 1 || s - end == 1) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void SequenceSet::Range::encode(Buffer& buffer) const
+{
+ buffer.putLong(start);
+ buffer.putLong(end);
+}
+
+SequenceSet::Range::Range(SequenceNumber s, SequenceNumber e) : start(s), end(e) {}
+
+namespace qpid{
+namespace framing{
+
+std::ostream& operator<<(std::ostream& out, const SequenceSet& set) {
+ out << "{";
+ for (SequenceSet::Ranges::const_iterator i = set.ranges.begin(); i != set.ranges.end(); i++) {
+ if (i != set.ranges.begin()) out << ", ";
+ out << i->start.getValue() << "-" << i->end.getValue();
+ }
+ out << "}";
+ return out;
+}
+
+}
+}
diff --git a/qpid/cpp/src/qpid/framing/SequenceSet.h b/qpid/cpp/src/qpid/framing/SequenceSet.h
new file mode 100644
index 0000000000..2f34cb5cba
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/SequenceSet.h
@@ -0,0 +1,86 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 <ostream>
+#include <list>
+#include "amqp_types.h"
+#include "Buffer.h"
+#include "SequenceNumber.h"
+#include "qpid/framing/reply_exceptions.h"
+
+namespace qpid {
+namespace framing {
+
+class SequenceSet
+{
+ struct Range
+ {
+ SequenceNumber start;
+ SequenceNumber end;
+
+ Range(SequenceNumber s, SequenceNumber e);
+ bool contains(SequenceNumber i) const;
+ bool intersects(const Range& r) const;
+ bool merge(const Range& r);
+ bool mergeable(const SequenceNumber& r) const;
+ void encode(Buffer& buffer) const;
+ };
+
+ typedef std::list<Range> Ranges;
+ Ranges ranges;
+
+public:
+ SequenceSet() {}
+ SequenceSet(const SequenceNumber& s) { add(s); }
+
+ void encode(Buffer& buffer) const;
+ void decode(Buffer& buffer);
+ uint32_t size() const;
+
+ bool contains(const SequenceNumber& s) const;
+ void add(const SequenceNumber& s);
+ void add(const SequenceNumber& start, const SequenceNumber& end);
+ void add(const SequenceSet& set);
+ void remove(const SequenceNumber& s);
+ void remove(const SequenceNumber& start, const SequenceNumber& end);
+ void remove(const SequenceSet& set);
+
+ void clear();
+ bool empty() const;
+
+ template <class T>
+ void for_each(T& t) const
+ {
+ for (Ranges::const_iterator i = ranges.begin(); i != ranges.end(); i++) {
+ t(i->start, i->end);
+ }
+ }
+
+ friend std::ostream& operator<<(std::ostream&, const SequenceSet&);
+};
+
+
+}} // namespace qpid::framing
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/framing/SerializeHandler.h b/qpid/cpp/src/qpid/framing/SerializeHandler.h
new file mode 100644
index 0000000000..55bd7da08c
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/SerializeHandler.h
@@ -0,0 +1,49 @@
+#ifndef QPID_FRAMING_SERIALIZEHANDLER_H
+#define QPID_FRAMING_SERIALIZEHANDLER_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/Serializer.h"
+#include "qpid/framing/Handler.h"
+
+#include <boost/bind.hpp>
+
+namespace qpid {
+namespace framing {
+
+
+/** Serializer that can be inserted into a Handler chain */
+template <class T>
+struct SerializeHandler : public framing::Handler<T>, public sys::Serializer {
+ SerializeHandler(typename framing::Handler<T>::Chain next)
+ : framing::Handler<T>(next) {}
+ void handle(T value) {
+ execute(boost::bind(&framing::Handler<T>::handle, this->next.get(), value));
+ }
+};
+
+}} // namespace qpid::framing
+
+
+
+
+
+#endif /*!QPID_FRAMING_SERIALIZEHANDLER_H*/
diff --git a/qpid/cpp/src/qpid/framing/SessionState.cpp b/qpid/cpp/src/qpid/framing/SessionState.cpp
new file mode 100644
index 0000000000..f9019b036c
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/SessionState.cpp
@@ -0,0 +1,137 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIE4bS 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/constants.h"
+#include "qpid/framing/AMQMethodBody.h"
+#include "qpid/log/Statement.h"
+
+#include <algorithm>
+
+#include <boost/bind.hpp>
+#include <boost/none.hpp>
+
+namespace qpid {
+namespace framing {
+
+SessionState::SessionState(uint32_t ack, bool enableReplay, const Uuid& uuid) :
+ state(ATTACHED),
+ id(uuid),
+ lastReceived(-1),
+ lastSent(-1),
+ ackInterval(ack),
+ sendAckAt(lastReceived+ackInterval),
+ solicitAckAt(lastSent+ackInterval),
+ ackSolicited(false),
+ resumable(enableReplay)
+{}
+
+SessionState::SessionState(const Uuid& uuid) :
+ state(ATTACHED),
+ id(uuid),
+ lastReceived(-1),
+ lastSent(-1),
+ ackInterval(0),
+ sendAckAt(0),
+ solicitAckAt(0),
+ ackSolicited(false),
+ resumable(false)
+{
+}
+namespace {
+bool isSessionCommand(const AMQFrame& f) {
+ return f.getMethod() && f.getMethod()->amqpClassId() == SESSION_CLASS_ID;
+}
+}
+
+boost::optional<SequenceNumber> SessionState::received(const AMQFrame& f) {
+ if (isSessionCommand(f))
+ return boost::none;
+ if (state==RESUMING)
+ throw CommandInvalidException(
+ QPID_MSG("Invalid frame: Resuming session, expected session-ack"));
+ assert(state = ATTACHED);
+ ++lastReceived;
+ if (ackInterval && lastReceived == sendAckAt)
+ return sendingAck();
+ else
+ return boost::none;
+}
+
+bool SessionState::sent(const AMQFrame& f) {
+ if (isSessionCommand(f))
+ return false;
+ if (resumable) {
+ sys::Mutex::ScopedLock l(unackedLock);
+ unackedOut.push_back(f);
+ }
+ ++lastSent;
+ return ackInterval &&
+ (state!=RESUMING) &&
+ (lastSent == solicitAckAt) &&
+ sendingSolicit();
+}
+
+SessionState::Replay SessionState::replay() {
+ sys::Mutex::ScopedLock l(unackedLock);
+ Replay r(unackedOut.size());
+ std::copy(unackedOut.begin(), unackedOut.end(), r.begin());
+ return r;
+}
+
+void SessionState::receivedAck(SequenceNumber acked) {
+ if (state==RESUMING) state=ATTACHED;
+ assert(state==ATTACHED);
+ if (lastSent < acked)
+ throw InvalidArgumentException("Invalid sequence number in ack");
+ size_t keep = lastSent - acked;
+ if (keep < unackedOut.size()) {
+ sys::Mutex::ScopedLock l(unackedLock);
+ unackedOut.erase(unackedOut.begin(), unackedOut.end()-keep);
+ }
+ solicitAckAt = std::max(solicitAckAt, SequenceNumber(acked+ackInterval));
+}
+
+SequenceNumber SessionState::sendingAck() {
+ sendAckAt = lastReceived+ackInterval;
+ return lastReceived;
+}
+
+bool SessionState::sendingSolicit() {
+ assert(state == ATTACHED);
+ if (ackSolicited)
+ return false;
+ solicitAckAt = lastSent + ackInterval;
+ return ackInterval != 0;
+}
+
+SequenceNumber SessionState::resuming() {
+ if (!resumable)
+ throw InternalErrorException("Session is not resumable");
+ state = RESUMING;
+ return sendingAck();
+}
+
+void SessionState::suspend() {
+ state = SUSPENDED;
+}
+
+}} // namespace qpid::framing
diff --git a/qpid/cpp/src/qpid/framing/SessionState.h b/qpid/cpp/src/qpid/framing/SessionState.h
new file mode 100644
index 0000000000..066bece003
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/SessionState.h
@@ -0,0 +1,138 @@
+#ifndef QPID_FRAMING_SESSIONSTATE_H
+#define QPID_FRAMING_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/framing/SequenceNumber.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/sys/Mutex.h"
+
+#include <boost/optional.hpp>
+
+#include <deque>
+
+namespace qpid {
+namespace framing {
+
+/**
+ * Session state common to client and broker.
+ * Stores replay frames, implements session ack/resume protcools.
+ *
+ * A SessionState is always associated with an _open_ session (attached or
+ * suspended) it is destroyed when the session is closed.
+ *
+ */
+class SessionState
+{
+ public:
+ typedef std::vector<AMQFrame> Replay;
+
+ /** States of a session. */
+ enum State {
+ SUSPENDED, ///< Suspended, detached from any channel.
+ RESUMING, ///< Resuming: waiting for initial ack from peer.
+ ATTACHED ///< Attached to channel and operating normally.
+ };
+
+ /**
+ *Create a newly opened active session.
+ *@param ackInterval send/solicit an ack whenever N unacked frames
+ * have been received/sent.
+ *
+ * N=0 disables voluntary send/solict ack.
+ */
+ SessionState(uint32_t ackInterval, bool enableReplay = true, const framing::Uuid& id=framing::Uuid(true));
+
+ /**
+ * Create a non-resumable session. Does not store session frames,
+ * never volunteers ack or solicit-ack.
+ */
+ SessionState(const framing::Uuid& id=framing::Uuid(true));
+
+ const framing::Uuid& getId() const { return id; }
+ State getState() const { return state; }
+
+ /** Received incoming L3 frame.
+ * @return SequenceNumber if an ack should be sent, empty otherwise.
+ * SessionState assumes that acks are sent whenever it returns
+ * a seq. number.
+ */
+ boost::optional<SequenceNumber> received(const AMQFrame&);
+
+ /** Sent outgoing L3 frame.
+ *@return true if solicit-ack should be sent. Note the SessionState
+ *assumes that a solicit-ack is sent every time it returns true.
+ */
+ bool sent(const AMQFrame&);
+
+ /** Received normal incoming ack. */
+ void receivedAck(SequenceNumber);
+
+ /** Frames to replay
+ *@pre getState()==ATTACHED
+ */
+ Replay replay();
+
+ /** Suspend the session. */
+ void suspend();
+
+ /** Start resume protocol for the session.
+ *@returns sequence number to ack immediately. */
+ SequenceNumber resuming();
+
+ /** About to send an unscheduled ack, e.g. to respond to a solicit-ack.
+ *
+ * Note: when received() returns a sequence number this function
+ * should not be called. SessionState assumes that the ack is sent
+ * every time received() returns a sequence number.
+ */
+ SequenceNumber sendingAck();
+
+ SequenceNumber getLastSent() const { return lastSent; }
+ SequenceNumber getLastReceived() const { return lastReceived; }
+
+ private:
+ typedef std::deque<AMQFrame> Unacked;
+
+ bool sendingSolicit();
+
+ State state;
+ framing::Uuid id;
+
+ Unacked unackedOut;
+ SequenceNumber lastReceived;
+ SequenceNumber lastSent;
+ uint32_t ackInterval;
+ SequenceNumber sendAckAt;
+ SequenceNumber solicitAckAt;
+ bool ackSolicited;
+ bool suspending;
+ bool resumable;
+ sys::Mutex unackedLock;
+};
+
+
+}} // namespace qpid::common
+
+
+#endif /*!QPID_FRAMING_SESSIONSTATE_H*/
diff --git a/qpid/cpp/src/qpid/framing/StructHelper.h b/qpid/cpp/src/qpid/framing/StructHelper.h
new file mode 100644
index 0000000000..ad6ba89906
--- /dev/null
+++ b/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.size() + 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/qpid/cpp/src/qpid/framing/TemplateVisitor.h b/qpid/cpp/src/qpid/framing/TemplateVisitor.h
new file mode 100644
index 0000000000..8c719e5110
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/framing/TransferContent.cpp b/qpid/cpp/src/qpid/framing/TransferContent.cpp
new file mode 100644
index 0000000000..99f5d365e8
--- /dev/null
+++ b/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& routingKey,
+ const std::string& exchange)
+{
+ setData(data);
+ if (routingKey.size()) getDeliveryProperties().setRoutingKey(routingKey);
+ if (exchange.size()) getDeliveryProperties().setExchange(exchange);
+}
+
+AMQHeaderBody TransferContent::getHeader() const
+{
+ return header;
+}
+
+const std::string& TransferContent::getData() const
+{
+ 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/qpid/cpp/src/qpid/framing/TransferContent.h b/qpid/cpp/src/qpid/framing/TransferContent.h
new file mode 100644
index 0000000000..88f45b7e0a
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/TransferContent.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 _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 {
+
+class TransferContent : public MethodContent
+{
+ AMQHeaderBody header;
+ std::string data;
+public:
+ TransferContent(const std::string& data = std::string(),
+ const std::string& routingKey = std::string(),
+ const std::string& exchange = std::string());
+
+ AMQHeaderBody getHeader() const;
+ void setData(const std::string&);
+ void appendData(const std::string&);
+ MessageProperties& getMessageProperties();
+ DeliveryProperties& getDeliveryProperties();
+
+ const std::string& getData() const;
+ const MessageProperties& getMessageProperties() const;
+ const DeliveryProperties& getDeliveryProperties() const;
+ bool hasMessageProperties() const;
+ bool hasDeliveryProperties() const;
+
+ void populate(const FrameSet& frameset);
+};
+
+}}
+#endif
diff --git a/qpid/cpp/src/qpid/framing/TypeFilter.h b/qpid/cpp/src/qpid/framing/TypeFilter.h
new file mode 100644
index 0000000000..d1c42de583
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/framing/Uuid.cpp b/qpid/cpp/src/qpid/framing/Uuid.cpp
new file mode 100644
index 0000000000..2918c48ce3
--- /dev/null
+++ b/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 SyntaxErrorException(QPID_MSG("Not enough data for UUID."));
+ buf.getRawData(c_array(), size());
+}
+
+ostream& operator<<(ostream& out, const 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/qpid/cpp/src/qpid/framing/Uuid.h b/qpid/cpp/src/qpid/framing/Uuid.h
new file mode 100644
index 0000000000..bce18f55b3
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/Uuid.h
@@ -0,0 +1,84 @@
+#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 <boost/array.hpp>
+
+#include <ostream>
+#include <istream>
+
+#include <uuid/uuid.h>
+
+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(const uint8_t* data) { assign(data); }
+
+ /** Copy from 16 bytes of data */
+ void assign(const 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() const { 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);
+
+ /** 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&, const 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/qpid/cpp/src/qpid/framing/Visitor.h b/qpid/cpp/src/qpid/framing/Visitor.h
new file mode 100644
index 0000000000..9753b21954
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/Visitor.h
@@ -0,0 +1,91 @@
+#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 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, must be forward declared, 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)...
+ * The odd parenthesized notation is 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)) \
+ {}
+
+/** Root class for 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;
+};
+
+/** 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/qpid/cpp/src/qpid/framing/amqp_framing.h b/qpid/cpp/src/qpid/framing/amqp_framing.h
new file mode 100644
index 0000000000..4e4747c3f4
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/framing/amqp_types.h b/qpid/cpp/src/qpid/framing/amqp_types.h
new file mode 100644
index 0000000000..943970cc56
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/amqp_types.h
@@ -0,0 +1,72 @@
+#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
+ * Type definitions and forward declarations of all types used to
+ * in AMQP messages.
+ */
+
+#include <string>
+#ifdef _WINDOWS
+#include "windows.h"
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned __int64 uint64_t;
+#endif
+#ifndef _WINDOWS
+#include <stdint.h>
+#endif
+
+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;
+class 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;
+class Uuid;
+
+}} // namespace qpid::framing
+#endif
diff --git a/qpid/cpp/src/qpid/framing/amqp_types_full.h b/qpid/cpp/src/qpid/framing/amqp_types_full.h
new file mode 100644
index 0000000000..da7bdc876d
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/amqp_types_full.h
@@ -0,0 +1,40 @@
+#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
+ * Type definitions and full declarations of all types used to
+ * in AMQP messages.
+ *
+ * Its 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 do increases compile
+ * times.
+ */
+
+#include "amqp_types.h"
+#include "Array.h"
+#include "FramingContent.h"
+#include "FieldTable.h"
+#include "SequenceNumberSet.h"
+#include "SequenceSet.h"
+#include "Uuid.h"
+
+#endif /*!_framing_amqp_types_decl_h*/
diff --git a/qpid/cpp/src/qpid/framing/frame_functors.h b/qpid/cpp/src/qpid/framing/frame_functors.h
new file mode 100644
index 0000000000..d915a270c2
--- /dev/null
+++ b/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.size(); }
+ uint64_t getSize() { return size; }
+};
+
+class SumBodySize
+{
+ uint64_t size;
+public:
+ SumBodySize() : size(0) {}
+ void operator()(const AMQFrame& f) { size += f.getBody()->size(); }
+ 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 a copy of the frame its applied to to the specified handler
+ */
+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/qpid/cpp/src/qpid/framing/variant.h b/qpid/cpp/src/qpid/framing/variant.h
new file mode 100644
index 0000000000..ceaed2c529
--- /dev/null
+++ b/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 exception if variant contains blank.
+ * Sublclasses need to have a using() declaration, 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 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 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 in a variant of variants */
+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/qpid/cpp/src/qpid/log/Helpers.h b/qpid/cpp/src/qpid/log/Helpers.h
new file mode 100644
index 0000000000..82ef8244be
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/log/Logger.cpp b/qpid/cpp/src/qpid/log/Logger.cpp
new file mode 100644
index 0000000000..c0fc8ac959
--- /dev/null
+++ b/qpid/cpp/src/qpid/log/Logger.cpp
@@ -0,0 +1,229 @@
+/*
+ *
+ * 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 "qpid/memory.h"
+#include "qpid/sys/Thread.h"
+#include <boost/pool/detail/singleton.hpp>
+#include <boost/bind.hpp>
+#include <boost/function.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <algorithm>
+#include <sstream>
+#include <fstream>
+#include <iomanip>
+#include <stdexcept>
+#include <syslog.h>
+#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);
+}
+
+struct OstreamOutput : public Logger::Output {
+ OstreamOutput(std::ostream& o) : out(&o) {}
+
+ OstreamOutput(const string& file)
+ : out(new ofstream(file.c_str())), mine(out)
+ {
+ if (!out->good())
+ throw std::runtime_error("Can't open log file: "+file);
+ }
+
+ void log(const Statement&, const std::string& m) {
+ *out << m << flush;
+ }
+
+ ostream* out;
+ boost::scoped_ptr<ostream> mine;
+};
+
+struct SyslogOutput : public Logger::Output {
+ SyslogOutput(const std::string& name, int facility_=LOG_USER)
+ : progName(name), facility(facility_)
+ {
+ ::openlog(name.c_str(), LOG_PID, facility);
+ }
+
+ ~SyslogOutput() {
+ ::closelog();
+ }
+
+ void log(const Statement& s, const std::string& m)
+ {
+ syslog(LevelTraits::priority(s.level), "%s", m.c_str());
+ }
+
+ std::string progName;
+ int facility;
+};
+
+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 (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 << "[" << 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::output(std::ostream& out) {
+ output(make_auto_ptr<Output>(new OstreamOutput(out)));
+}
+
+void Logger::syslog(const std::string& progName) {
+ output(make_auto_ptr<Output>(new SyslogOutput(progName)));
+}
+
+void Logger::output(const std::string& name) {
+ if (name=="stderr")
+ output(clog);
+ else if (name=="stdout")
+ output(cout);
+ else if (name=="syslog")
+ syslog(syslogName);
+ else
+ output(make_auto_ptr<Output>(new OstreamOutput(name)));
+}
+
+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, const std::string& prog)
+{
+ clear();
+ Options o(opts);
+ if (o.trace)
+ o.selectors.push_back("trace+");
+ {
+ ScopedLock l(lock);
+ syslogName=prog;
+ }
+ format(o);
+ select(Selector(o));
+ void (Logger::* outputFn)(const std::string&) = &Logger::output;
+ for_each(o.outputs.begin(), o.outputs.end(),
+ boost::bind(outputFn, this, _1));
+}
+
+}} // namespace qpid::log
diff --git a/qpid/cpp/src/qpid/log/Logger.h b/qpid/cpp/src/qpid/log/Logger.h
new file mode 100644
index 0000000000..7851c65406
--- /dev/null
+++ b/qpid/cpp/src/qpid/log/Logger.h
@@ -0,0 +1,113 @@
+#ifndef LOGGER_H
+#define 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 "qpid/sys/Mutex.h"
+#include <boost/ptr_container/ptr_vector.hpp>
+#include <boost/noncopyable.hpp>
+#include <set>
+
+namespace qpid {
+namespace log {
+
+class Options;
+
+/**
+ * Central logging agent.
+ *
+ * Thread safe, singleton.
+ */
+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};
+
+ /** Interface for log output destination.
+ *
+ * Implementations 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, const std::string& progname);
+
+ /** Add a statement. */
+ void add(Statement& s);
+
+ /** Log a message. */
+ void log(const Statement&, const std::string&);
+
+ /** Add an ostream to outputs.
+ *
+ * The ostream must not be destroyed while the Logger might
+ * still be using it. This is the case for std streams cout,
+ * cerr, clog.
+ */
+ void output(std::ostream&);
+
+ /** Add syslog to outputs. */
+ void syslog(const std::string& programName);
+
+ /** Add an output.
+ *@param name a file name or one of the special tokens:
+ *stdout, stderr, syslog.
+ */
+ void output(const std::string& name);
+
+ /** Add an output destination for messages */
+ void output(std::auto_ptr<Output> out);
+
+ /** Reset the logger to it's original state. */
+ void clear();
+
+ private:
+ typedef boost::ptr_vector<Output> Outputs;
+ typedef std::set<Statement*> Statements;
+
+ sys::Mutex lock;
+ inline void enable_unlocked(Statement* s);
+
+ std::string syslogName;
+ Statements statements;
+ Outputs outputs;
+ Selector selector;
+ int flags;
+};
+
+}} // namespace qpid::log
+
+
+#endif /*!LOGGER_H*/
diff --git a/qpid/cpp/src/qpid/log/Options.cpp b/qpid/cpp/src/qpid/log/Options.cpp
new file mode 100644
index 0000000000..dd296f3a93
--- /dev/null
+++ b/qpid/cpp/src/qpid/log/Options.cpp
@@ -0,0 +1,66 @@
+/*
+ *
+ * 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 "Statement.h"
+#include "qpid/Options.h"
+
+namespace qpid {
+namespace log {
+
+using namespace std;
+
+Options::Options(const std::string& name) : qpid::Options(name),
+ time(true), level(true), thread(false), source(false), function(false), trace(false)
+{
+ outputs.push_back("stderr");
+ selectors.push_back("error+");
+
+ ostringstream levels;
+ levels << LevelTraits::name(Level(0));
+ for (int i = 1; i < LevelTraits::COUNT; ++i)
+ levels << " " << LevelTraits::name(Level(i));
+ addOptions()
+ ("log-output", optValue(outputs, "FILE"),
+ "Send log output to FILE. "
+ "FILE can be a file name or one of the special values:\n"
+ "stderr, stdout, syslog")
+ ("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");
+}
+
+}} // namespace qpid::log
diff --git a/qpid/cpp/src/qpid/log/Options.h b/qpid/cpp/src/qpid/log/Options.h
new file mode 100644
index 0000000000..441c6e8a8d
--- /dev/null
+++ b/qpid/cpp/src/qpid/log/Options.h
@@ -0,0 +1,42 @@
+#ifndef OPTIONS_H
+#define 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"
+
+
+namespace qpid {
+namespace log {
+
+/** Logging options for config parser. */
+struct Options : public qpid::Options {
+ Options(const std::string& name="Logging options");
+
+ std::vector<std::string> selectors;
+ std::vector<std::string> outputs;
+ bool time, level, thread, source, function;
+ bool trace;
+};
+
+
+}} // namespace qpid::log
+
+
+
+#endif /*!OPTIONS_H*/
diff --git a/qpid/cpp/src/qpid/log/Selector.cpp b/qpid/cpp/src/qpid/log/Selector.cpp
new file mode 100644
index 0000000000..994421d0ff
--- /dev/null
+++ b/qpid/cpp/src/qpid/log/Selector.cpp
@@ -0,0 +1,66 @@
+/*
+ *
+ * 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 std::string& function) {
+ for (std::vector<std::string>::iterator i=substrings[level].begin();
+ i != substrings[level].end();
+ ++i)
+ {
+ if (function.find(*i) != std::string::npos)
+ return true;
+ }
+ return false;
+}
+
+}} // namespace qpid::log
diff --git a/qpid/cpp/src/qpid/log/Selector.h b/qpid/cpp/src/qpid/log/Selector.h
new file mode 100644
index 0000000000..7c98bc6f8f
--- /dev/null
+++ b/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 {
+class 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 enabld for file. */
+ bool isEnabled(Level level, const std::string& function);
+
+ private:
+ std::vector<std::string> substrings[LevelTraits::COUNT];
+};
+
+
+}} // namespace qpid::log
+
+
+#endif /*!SELECTOR_H*/
diff --git a/qpid/cpp/src/qpid/log/Statement.cpp b/qpid/cpp/src/qpid/log/Statement.cpp
new file mode 100644
index 0000000000..db5d92c50a
--- /dev/null
+++ b/qpid/cpp/src/qpid/log/Statement.cpp
@@ -0,0 +1,92 @@
+/*
+ *
+ * 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 <syslog.h>
+#include <ctype.h>
+
+namespace qpid {
+namespace log {
+
+namespace {
+using namespace std;
+
+struct NonPrint { bool operator()(unsigned char c) { return !isprint(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(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"
+};
+
+int priorities[LevelTraits::COUNT] = {
+ LOG_DEBUG, LOG_DEBUG, LOG_INFO, LOG_NOTICE,
+ LOG_WARNING, LOG_ERR, LOG_CRIT
+};
+
+} // 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];
+}
+
+int LevelTraits::priority(Level l) {
+ return priorities[l];
+}
+
+}} // namespace qpid::log
diff --git a/qpid/cpp/src/qpid/log/Statement.h b/qpid/cpp/src/qpid/log/Statement.h
new file mode 100644
index 0000000000..18162971b0
--- /dev/null
+++ b/qpid/cpp/src/qpid/log/Statement.h
@@ -0,0 +1,114 @@
+#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);
+
+ /** Syslog priority of level */
+ static int priority(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) }
+
+/**
+ * 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
+ *
+ * All code with logging statements should be built with
+ * -DQPID_COMPONENT=<component name>
+ * where component name is the name of the component this file belongs to.
+ *
+ * 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) \
+ do { \
+ static ::qpid::log::Statement stmt_= QPID_LOG_STATEMENT_INIT(level); \
+ static ::qpid::log::Statement::Initializer init_(stmt_); \
+ if (stmt_.enabled) \
+ stmt_.log(::qpid::Msg() << message); \
+ } while(0)
+
+}} // namespace qpid::log
+
+
+
+
+#endif /*!STATEMENT_H*/
+
diff --git a/qpid/cpp/src/qpid/management/Args.h b/qpid/cpp/src/qpid/management/Args.h
new file mode 100644
index 0000000000..da1fb033b9
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/management/Manageable.cpp b/qpid/cpp/src/qpid/management/Manageable.cpp
new file mode 100644
index 0000000000..479cb4e0ce
--- /dev/null
+++ b/qpid/cpp/src/qpid/management/Manageable.cpp
@@ -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 "Manageable.h"
+
+using namespace qpid::management;
+
+std::string Manageable::StatusText (status_t status)
+{
+ 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";
+ }
+
+ return "??";
+}
+
diff --git a/qpid/cpp/src/qpid/management/Manageable.h b/qpid/cpp/src/qpid/management/Manageable.h
new file mode 100644
index 0000000000..836ba03b23
--- /dev/null
+++ b/qpid/cpp/src/qpid/management/Manageable.h
@@ -0,0 +1,68 @@
+#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>
+#include <boost/shared_ptr.hpp>
+
+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);
+
+ 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;
+
+ // 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 shared_ptr to the management object.
+ //
+ virtual ManagementObject::shared_ptr 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) = 0;
+};
+
+inline Manageable::~Manageable (void) {}
+
+}}
+
+#endif /*!_Manageable_*/
diff --git a/qpid/cpp/src/qpid/management/ManagementAgent.cpp b/qpid/cpp/src/qpid/management/ManagementAgent.cpp
new file mode 100644
index 0000000000..ee0eb27bf6
--- /dev/null
+++ b/qpid/cpp/src/qpid/management/ManagementAgent.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 "ManagementAgent.h"
+#include "qpid/broker/DeliverableMessage.h"
+#include "qpid/log/Statement.h"
+#include <qpid/broker/Message.h>
+#include <qpid/broker/MessageDelivery.h>
+#include <list>
+#include <iostream>
+#include <fstream>
+
+using boost::intrusive_ptr;
+using namespace qpid::framing;
+using namespace qpid::management;
+using namespace qpid::broker;
+using namespace qpid::sys;
+using namespace std;
+
+ManagementAgent::shared_ptr ManagementAgent::agent;
+bool ManagementAgent::enabled = 0;
+
+ManagementAgent::ManagementAgent (string _dataDir, uint16_t _interval) :
+ dataDir (_dataDir), interval (_interval)
+{
+ timer.add (intrusive_ptr<TimerTask> (new Periodic(*this, interval)));
+ nextObjectId = uint64_t (qpid::sys::Duration (qpid::sys::now ()));
+ nextRemotePrefix = 101;
+
+ // Get from file or generate and save to file.
+ if (dataDir.empty ())
+ {
+ uuid.generate ();
+ QPID_LOG (info, "ManagementAgent has no data directory, generated new broker ID: "
+ << uuid);
+ }
+ else
+ {
+ string filename (dataDir + "/brokerId");
+ ifstream inFile (filename.c_str ());
+
+ if (inFile.good ())
+ {
+ inFile >> uuid;
+ inFile.close ();
+ QPID_LOG (debug, "ManagementAgent restored broker ID: " << uuid);
+ }
+ else
+ {
+ uuid.generate ();
+ QPID_LOG (info, "ManagementAgent generated broker ID: " << uuid);
+
+ ofstream outFile (filename.c_str ());
+ if (outFile.good ())
+ {
+ outFile << uuid << endl;
+ outFile.close ();
+ QPID_LOG (debug, "ManagementAgent saved broker ID");
+ }
+ else
+ {
+ QPID_LOG (warning, "ManagementAgent unable to save broker ID");
+ }
+ }
+ }
+}
+
+ManagementAgent::~ManagementAgent () {}
+
+void ManagementAgent::enableManagement (string dataDir, uint16_t interval)
+{
+ enabled = 1;
+ if (agent.get () == 0)
+ agent = shared_ptr (new ManagementAgent (dataDir, interval));
+}
+
+ManagementAgent::shared_ptr ManagementAgent::getAgent (void)
+{
+ return agent;
+}
+
+void ManagementAgent::shutdown (void)
+{
+ if (agent.get () != 0)
+ {
+ agent->mExchange.reset ();
+ agent->dExchange.reset ();
+ agent.reset ();
+ }
+}
+
+void ManagementAgent::setExchange (broker::Exchange::shared_ptr _mexchange,
+ broker::Exchange::shared_ptr _dexchange)
+{
+ mExchange = _mexchange;
+ dExchange = _dexchange;
+}
+
+void ManagementAgent::RegisterClass (string packageName,
+ string className,
+ uint8_t* md5Sum,
+ ManagementObject::writeSchemaCall_t schemaCall)
+{
+ Mutex::ScopedLock lock (userLock);
+ PackageMap::iterator pIter = FindOrAddPackage (packageName);
+ AddClassLocal (pIter, className, md5Sum, schemaCall);
+}
+
+void ManagementAgent::addObject (ManagementObject::shared_ptr object,
+ uint64_t /*persistenceId*/,
+ uint64_t /*idOffset*/)
+{
+ Mutex::ScopedLock lock (userLock);
+ uint64_t objectId;
+
+// if (persistenceId == 0)
+ objectId = nextObjectId++;
+// else
+// objectId = 0x8000000000000000ULL | (persistenceId + idOffset);
+
+ object->setObjectId (objectId);
+ managementObjects[objectId] = object;
+}
+
+ManagementAgent::Periodic::Periodic (ManagementAgent& _agent, uint32_t _seconds)
+ : TimerTask (qpid::sys::Duration (_seconds * qpid::sys::TIME_SEC)), agent(_agent) {}
+
+ManagementAgent::Periodic::~Periodic () {}
+
+void ManagementAgent::Periodic::fire ()
+{
+ agent.timer.add (intrusive_ptr<TimerTask> (new Periodic (agent, agent.interval)));
+ agent.PeriodicProcessing ();
+}
+
+void ManagementAgent::clientAdded (void)
+{
+ for (ManagementObjectMap::iterator iter = managementObjects.begin ();
+ iter != managementObjects.end ();
+ iter++)
+ {
+ ManagementObject::shared_ptr object = iter->second;
+ object->setAllChanged ();
+ }
+}
+
+void ManagementAgent::EncodeHeader (Buffer& buf, uint8_t opcode, uint32_t seq)
+{
+ buf.putOctet ('A');
+ buf.putOctet ('M');
+ buf.putOctet ('1');
+ buf.putOctet (opcode);
+ buf.putLong (seq);
+}
+
+bool ManagementAgent::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 == '1';
+}
+
+void ManagementAgent::SendBuffer (Buffer& buf,
+ uint32_t length,
+ broker::Exchange::shared_ptr exchange,
+ string routingKey)
+{
+ if (exchange.get() == 0)
+ return;
+
+ intrusive_ptr<Message> msg (new Message ());
+ AMQFrame method (in_place<MessageTransferBody>(
+ ProtocolVersion(), 0, 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);
+ exchange->route (deliverable, routingKey, 0);
+}
+
+void ManagementAgent::PeriodicProcessing (void)
+{
+#define BUFSIZE 65536
+ Mutex::ScopedLock lock (userLock);
+ char msgChars[BUFSIZE];
+ uint32_t contentSize;
+ string routingKey;
+ std::list<uint64_t> deleteList;
+
+ if (managementObjects.empty ())
+ return;
+
+ for (ManagementObjectMap::iterator iter = managementObjects.begin ();
+ iter != managementObjects.end ();
+ iter++)
+ {
+ ManagementObject::shared_ptr object = iter->second;
+
+ if (object->getConfigChanged () || object->isDeleted ())
+ {
+ Buffer msgBuffer (msgChars, BUFSIZE);
+ EncodeHeader (msgBuffer, 'c');
+ object->writeConfig (msgBuffer);
+
+ contentSize = BUFSIZE - msgBuffer.available ();
+ msgBuffer.reset ();
+ routingKey = "mgmt." + uuid.str() + ".config." + object->getClassName ();
+ SendBuffer (msgBuffer, contentSize, mExchange, routingKey);
+ }
+
+ if (object->getInstChanged ())
+ {
+ Buffer msgBuffer (msgChars, BUFSIZE);
+ EncodeHeader (msgBuffer, 'i');
+ object->writeInstrumentation (msgBuffer);
+
+ contentSize = BUFSIZE - msgBuffer.available ();
+ msgBuffer.reset ();
+ routingKey = "mgmt." + uuid.str () + ".inst." + object->getClassName ();
+ SendBuffer (msgBuffer, contentSize, mExchange, routingKey);
+ }
+
+ if (object->isDeleted ())
+ deleteList.push_back (iter->first);
+ }
+
+ // Delete flagged objects
+ for (std::list<uint64_t>::reverse_iterator iter = deleteList.rbegin ();
+ iter != deleteList.rend ();
+ iter++)
+ managementObjects.erase (*iter);
+
+ deleteList.clear ();
+}
+
+void ManagementAgent::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);
+}
+
+void ManagementAgent::dispatchCommand (Deliverable& deliverable,
+ const string& routingKey,
+ const FieldTable* /*args*/)
+{
+ Mutex::ScopedLock lock (userLock);
+ Message& msg = ((DeliverableMessage&) deliverable).getMessage ();
+
+ if (routingKey.compare (0, 13, "agent.method.") == 0)
+ dispatchMethod (msg, routingKey, 13);
+
+ else if (routingKey.length () == 5 &&
+ routingKey.compare (0, 5, "agent") == 0)
+ dispatchAgentCommand (msg);
+
+ else
+ {
+ QPID_LOG (debug, "Illegal routing key for dispatch: " << routingKey);
+ return;
+ }
+}
+
+void ManagementAgent::dispatchMethod (Message& msg,
+ const string& routingKey,
+ size_t first)
+{
+ size_t pos, start = first;
+ uint32_t contentSize;
+
+ if (routingKey.length () == start)
+ {
+ QPID_LOG (debug, "Missing package-name in routing key: " << routingKey);
+ return;
+ }
+
+ pos = routingKey.find ('.', start);
+ if (pos == string::npos || routingKey.length () == pos + 1)
+ {
+ QPID_LOG (debug, "Missing class-name in routing key: " << routingKey);
+ return;
+ }
+
+ string packageName = routingKey.substr (start, pos - start);
+
+ start = pos + 1;
+ pos = routingKey.find ('.', start);
+ if (pos == string::npos || routingKey.length () == pos + 1)
+ {
+ QPID_LOG (debug, "Missing method-name in routing key: " << routingKey);
+ return;
+ }
+
+ string className = routingKey.substr (start, pos - start);
+
+ start = pos + 1;
+ string methodName = routingKey.substr (start, routingKey.length () - start);
+
+ contentSize = msg.encodedContentSize ();
+ if (contentSize < 8 || contentSize > MA_BUFFER_SIZE)
+ return;
+
+ Buffer inBuffer (inputBuffer, MA_BUFFER_SIZE);
+ Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen, sequence;
+ uint8_t opcode;
+
+ msg.encodeContent (inBuffer);
+ inBuffer.reset ();
+
+ if (!CheckHeader (inBuffer, &opcode, &sequence))
+ {
+ QPID_LOG (debug, " Invalid content header");
+ return;
+ }
+
+ if (opcode != 'M')
+ {
+ QPID_LOG (debug, " Unexpected opcode " << opcode);
+ return;
+ }
+
+ uint64_t objId = inBuffer.getLongLong ();
+ 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
+ {
+ QPID_LOG (debug, " Reply-to missing");
+ return;
+ }
+
+ EncodeHeader (outBuffer, 'm', sequence);
+
+ ManagementObjectMap::iterator iter = managementObjects.find (objId);
+ if (iter == managementObjects.end ())
+ {
+ outBuffer.putLong (Manageable::STATUS_UNKNOWN_OBJECT);
+ outBuffer.putShortString (Manageable::StatusText (Manageable::STATUS_UNKNOWN_OBJECT));
+ }
+ else
+ {
+ iter->second->doMethod (methodName, inBuffer, outBuffer);
+ }
+
+ outLen = MA_BUFFER_SIZE - outBuffer.available ();
+ outBuffer.reset ();
+ SendBuffer (outBuffer, outLen, dExchange, replyToKey);
+}
+
+void ManagementAgent::handleBrokerRequest (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 ManagementAgent::handlePackageQuery (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 ManagementAgent::handlePackageInd (Buffer& inBuffer, string /*replyToKey*/, uint32_t /*sequence*/)
+{
+ std::string packageName;
+
+ inBuffer.getShortString (packageName);
+ FindOrAddPackage (packageName);
+}
+
+void ManagementAgent::handleClassQuery (Buffer& inBuffer, string replyToKey, uint32_t sequence)
+{
+ std::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++)
+ {
+ 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 ManagementAgent::handleSchemaQuery (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.writeSchemaCall != 0)
+ {
+ EncodeHeader (outBuffer, 's', sequence);
+ classInfo.writeSchemaCall (outBuffer);
+ outLen = MA_BUFFER_SIZE - outBuffer.available ();
+ outBuffer.reset ();
+ SendBuffer (outBuffer, outLen, dExchange, replyToKey);
+ }
+ else
+ {
+ // TODO: Forward request to remote agent.
+ }
+
+ clientAdded ();
+ // TODO: Send client-added to each remote agent.
+ }
+ }
+}
+
+uint32_t ManagementAgent::assignPrefix (uint32_t /*requestedPrefix*/)
+{
+ // TODO: Allow remote agents to keep their requested prefixes if able.
+ return nextRemotePrefix++;
+}
+
+void ManagementAgent::handleAttachRequest (Buffer& inBuffer, string replyToKey, uint32_t sequence)
+{
+ string label;
+ uint32_t requestedPrefix;
+ uint32_t assignedPrefix;
+
+ inBuffer.getShortString (label);
+ requestedPrefix = inBuffer.getLong ();
+ assignedPrefix = assignPrefix (requestedPrefix);
+
+ Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ EncodeHeader (outBuffer, 'a', sequence);
+ outBuffer.putLong (assignedPrefix);
+ outLen = MA_BUFFER_SIZE - outBuffer.available ();
+ outBuffer.reset ();
+ SendBuffer (outBuffer, outLen, dExchange, replyToKey);
+}
+
+void ManagementAgent::handleGetRequest (Buffer& inBuffer, string replyToKey, uint32_t sequence)
+{
+ FieldTable ft;
+ FieldTable::ValuePtr value;
+
+ ft.decode (inBuffer);
+ value = ft.get ("_class");
+ if (value->empty () || !value->convertsTo<string> ())
+ {
+ // TODO: Send completion with an error code
+ return;
+ }
+
+ string className (value->get<string> ());
+
+ for (ManagementObjectMap::iterator iter = managementObjects.begin ();
+ iter != managementObjects.end ();
+ iter++)
+ {
+ ManagementObject::shared_ptr object = iter->second;
+ if (object->getClassName () == className)
+ {
+ Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ EncodeHeader (outBuffer, 'g', sequence);
+ object->writeConfig (outBuffer);
+ object->writeInstrumentation (outBuffer, true);
+ outLen = MA_BUFFER_SIZE - outBuffer.available ();
+ outBuffer.reset ();
+ SendBuffer (outBuffer, outLen, dExchange, replyToKey);
+ }
+ }
+
+ sendCommandComplete (replyToKey, sequence);
+}
+
+void ManagementAgent::dispatchAgentCommand (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;
+
+ msg.encodeContent (inBuffer);
+ inBuffer.reset ();
+
+ if (!CheckHeader (inBuffer, &opcode, &sequence))
+ return;
+
+ if (opcode == 'B') handleBrokerRequest (inBuffer, replyToKey, sequence);
+ else if (opcode == 'P') handlePackageQuery (inBuffer, replyToKey, sequence);
+ else if (opcode == 'p') handlePackageInd (inBuffer, replyToKey, sequence);
+ else if (opcode == 'Q') handleClassQuery (inBuffer, replyToKey, sequence);
+ else if (opcode == 'S') handleSchemaQuery (inBuffer, replyToKey, sequence);
+ else if (opcode == 'A') handleAttachRequest (inBuffer, replyToKey, sequence);
+ else if (opcode == 'G') handleGetRequest (inBuffer, replyToKey, sequence);
+}
+
+ManagementAgent::PackageMap::iterator ManagementAgent::FindOrAddPackage (std::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, "ManagementAgent 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, "mgmt." + uuid.str() + ".schema.package");
+
+ return result.first;
+}
+
+void ManagementAgent::AddClassLocal (PackageMap::iterator pIter,
+ 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, "ManagementAgent added class " << pIter->first << "." <<
+ key.name);
+ SchemaClass classInfo;
+
+ classInfo.writeSchemaCall = schemaCall;
+ cMap[key] = classInfo;
+
+ // TODO: Publish a class-indication message
+}
+
+void ManagementAgent::EncodePackageIndication (Buffer& buf,
+ PackageMap::iterator pIter)
+{
+ buf.putShortString ((*pIter).first);
+}
+
+void ManagementAgent::EncodeClassIndication (Buffer& buf,
+ PackageMap::iterator pIter,
+ ClassMap::iterator cIter)
+{
+ SchemaClassKey key = (*cIter).first;
+
+ buf.putShortString ((*pIter).first);
+ buf.putShortString (key.name);
+ buf.putBin128 (key.hash);
+}
+
diff --git a/qpid/cpp/src/qpid/management/ManagementAgent.h b/qpid/cpp/src/qpid/management/ManagementAgent.h
new file mode 100644
index 0000000000..bd86d4e773
--- /dev/null
+++ b/qpid/cpp/src/qpid/management/ManagementAgent.h
@@ -0,0 +1,189 @@
+#ifndef _ManagementAgent_
+#define _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/Options.h"
+#include "qpid/broker/Exchange.h"
+#include "qpid/broker/Timer.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/sys/Mutex.h"
+#include "ManagementObject.h"
+#include <qpid/framing/AMQFrame.h>
+#include <boost/shared_ptr.hpp>
+
+namespace qpid {
+namespace management {
+
+class ManagementAgent
+{
+ private:
+
+ ManagementAgent (std::string dataDir, uint16_t interval);
+
+ public:
+
+ virtual ~ManagementAgent ();
+
+ typedef boost::shared_ptr<ManagementAgent> shared_ptr;
+
+ static void enableManagement (std::string dataDir, uint16_t interval);
+ static shared_ptr getAgent (void);
+ static void shutdown (void);
+
+ void setInterval (uint16_t _interval) { interval = _interval; }
+ void setExchange (broker::Exchange::shared_ptr mgmtExchange,
+ broker::Exchange::shared_ptr directExchange);
+ void RegisterClass (std::string packageName,
+ std::string className,
+ uint8_t* md5Sum,
+ ManagementObject::writeSchemaCall_t schemaCall);
+ void addObject (ManagementObject::shared_ptr object,
+ uint64_t persistenceId = 0,
+ uint64_t idOffset = 10);
+ void clientAdded (void);
+ void dispatchCommand (broker::Deliverable& msg,
+ const std::string& routingKey,
+ const qpid::framing::FieldTable* args);
+
+ private:
+
+ struct Periodic : public broker::TimerTask
+ {
+ ManagementAgent& agent;
+
+ Periodic (ManagementAgent& agent, uint32_t seconds);
+ virtual ~Periodic ();
+ void fire ();
+ };
+
+ // Storage for tracking remote management agents, attached via the client
+ // management agent API.
+ //
+ struct RemoteAgent
+ {
+ std::string name;
+ uint64_t objIdBase;
+ };
+
+ // 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<std::string, 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
+ {
+ ManagementObject::writeSchemaCall_t writeSchemaCall;
+ ReplyToVector remoteAgents;
+
+ SchemaClass () : writeSchemaCall(0) {}
+ };
+
+ typedef std::map<SchemaClassKey, SchemaClass, SchemaClassKeyComp> ClassMap;
+ typedef std::map<std::string, ClassMap> PackageMap;
+
+ RemoteAgentMap remoteAgents;
+ PackageMap packages;
+ ManagementObjectMap managementObjects;
+
+ static shared_ptr agent;
+ static bool enabled;
+
+ qpid::framing::Uuid uuid;
+ qpid::sys::Mutex userLock;
+ broker::Timer timer;
+ broker::Exchange::shared_ptr mExchange;
+ broker::Exchange::shared_ptr dExchange;
+ std::string dataDir;
+ uint16_t interval;
+ uint64_t nextObjectId;
+ uint32_t nextRemotePrefix;
+
+# define MA_BUFFER_SIZE 65536
+ char inputBuffer[MA_BUFFER_SIZE];
+ char outputBuffer[MA_BUFFER_SIZE];
+
+ void PeriodicProcessing (void);
+ void EncodeHeader (qpid::framing::Buffer& buf, uint8_t opcode, uint32_t seq = 0);
+ bool CheckHeader (qpid::framing::Buffer& buf, uint8_t *opcode, uint32_t *seq);
+ void SendBuffer (qpid::framing::Buffer& buf,
+ uint32_t length,
+ broker::Exchange::shared_ptr exchange,
+ std::string routingKey);
+
+ void dispatchMethod (broker::Message& msg,
+ const std::string& routingKey,
+ size_t first);
+ void dispatchAgentCommand (broker::Message& msg);
+
+ PackageMap::iterator FindOrAddPackage (std::string name);
+ void AddClassLocal (PackageMap::iterator pIter,
+ std::string className,
+ uint8_t* md5Sum,
+ ManagementObject::writeSchemaCall_t schemaCall);
+ void EncodePackageIndication (qpid::framing::Buffer& buf,
+ PackageMap::iterator pIter);
+ void EncodeClassIndication (qpid::framing::Buffer& buf,
+ PackageMap::iterator pIter,
+ ClassMap::iterator cIter);
+ uint32_t assignPrefix (uint32_t requestedPrefix);
+ void sendCommandComplete (std::string replyToKey, uint32_t sequence,
+ uint32_t code = 0, std::string text = std::string("OK"));
+ void handleBrokerRequest (qpid::framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
+ void handlePackageQuery (qpid::framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
+ void handlePackageInd (qpid::framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
+ void handleClassQuery (qpid::framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
+ void handleSchemaQuery (qpid::framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
+ void handleAttachRequest (qpid::framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
+ void handleGetRequest (qpid::framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
+};
+
+}}
+
+#endif /*!_ManagementAgent_*/
diff --git a/qpid/cpp/src/qpid/management/ManagementExchange.cpp b/qpid/cpp/src/qpid/management/ManagementExchange.cpp
new file mode 100644
index 0000000000..c589aefba0
--- /dev/null
+++ b/qpid/cpp/src/qpid/management/ManagementExchange.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 "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)
+{
+ // Intercept management agent commands
+ if ((routingKey.length () > 6 &&
+ routingKey.substr (0, 6).compare ("agent.") == 0) ||
+ (routingKey.length () == 5 &&
+ routingKey.substr (0, 5).compare ("agent") == 0))
+ {
+ managementAgent->dispatchCommand (msg, routingKey, args);
+ return;
+ }
+
+ TopicExchange::route (msg, routingKey, args);
+}
+
+void ManagementExchange::setManagmentAgent (ManagementAgent::shared_ptr agent)
+{
+ managementAgent = agent;
+}
+
+
+ManagementExchange::~ManagementExchange() {}
+
+const std::string ManagementExchange::typeName("management");
+
diff --git a/qpid/cpp/src/qpid/management/ManagementExchange.h b/qpid/cpp/src/qpid/management/ManagementExchange.h
new file mode 100644
index 0000000000..7faec32b0f
--- /dev/null
+++ b/qpid/cpp/src/qpid/management/ManagementExchange.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 _ManagementExchange_
+#define _ManagementExchange_
+
+#include "qpid/broker/TopicExchange.h"
+#include "ManagementAgent.h"
+
+namespace qpid {
+namespace broker {
+
+class ManagementExchange : public virtual TopicExchange
+{
+ private:
+ management::ManagementAgent::shared_ptr 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);
+
+ void setManagmentAgent (management::ManagementAgent::shared_ptr agent);
+
+ virtual ~ManagementExchange();
+};
+
+
+}
+}
+
+#endif
diff --git a/qpid/cpp/src/qpid/management/ManagementObject.cpp b/qpid/cpp/src/qpid/management/ManagementObject.cpp
new file mode 100644
index 0000000000..6af5412b99
--- /dev/null
+++ b/qpid/cpp/src/qpid/management/ManagementObject.cpp
@@ -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.
+ *
+ */
+
+#include "Manageable.h"
+#include "ManagementObject.h"
+#include "qpid/framing/FieldTable.h"
+
+using namespace qpid::framing;
+using namespace qpid::management;
+using namespace qpid::sys;
+
+void ManagementObject::writeTimestamps (Buffer& buf)
+{
+ buf.putShortString (getPackageName ());
+ buf.putShortString (getClassName ());
+ buf.putBin128 (getMd5Sum ());
+ buf.putLongLong (uint64_t (Duration (now ())));
+ buf.putLongLong (createTime);
+ buf.putLongLong (destroyTime);
+ buf.putLongLong (objectId);
+}
diff --git a/qpid/cpp/src/qpid/management/ManagementObject.h b/qpid/cpp/src/qpid/management/ManagementObject.h
new file mode 100644
index 0000000000..48a3372d16
--- /dev/null
+++ b/qpid/cpp/src/qpid/management/ManagementObject.h
@@ -0,0 +1,125 @@
+#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 "Manageable.h"
+#include "qpid/sys/Time.h"
+#include "qpid/sys/Mutex.h"
+#include <qpid/framing/Buffer.h>
+#include <boost/shared_ptr.hpp>
+#include <map>
+
+namespace qpid {
+namespace management {
+
+class Manageable;
+
+class ManagementObject
+{
+ protected:
+
+ uint64_t createTime;
+ uint64_t destroyTime;
+ uint64_t objectId;
+ bool configChanged;
+ bool instChanged;
+ bool deleted;
+ Manageable* coreObject;
+ sys::RWlock accessLock;
+
+ 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 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;
+
+ void writeTimestamps (qpid::framing::Buffer& buf);
+
+ public:
+ typedef boost::shared_ptr<ManagementObject> shared_ptr;
+ typedef void (*writeSchemaCall_t) (qpid::framing::Buffer&);
+
+ ManagementObject (Manageable* _core) :
+ destroyTime(0), objectId (0), configChanged(true),
+ instChanged(true), deleted(false), coreObject(_core)
+ { createTime = uint64_t (qpid::sys::Duration (qpid::sys::now ())); }
+ virtual ~ManagementObject () {}
+
+ virtual writeSchemaCall_t getWriteSchemaCall (void) = 0;
+ virtual void writeConfig (qpid::framing::Buffer& buf) = 0;
+ virtual void writeInstrumentation (qpid::framing::Buffer& buf,
+ bool skipHeaders = false) = 0;
+ virtual void doMethod (std::string methodName,
+ qpid::framing::Buffer& inBuf,
+ qpid::framing::Buffer& outBuf) = 0;
+
+ virtual std::string getClassName (void) = 0;
+ virtual std::string getPackageName (void) = 0;
+ virtual uint8_t* getMd5Sum (void) = 0;
+
+ void setObjectId (uint64_t oid) { objectId = oid; }
+ uint64_t getObjectId (void) { return objectId; }
+ inline bool getConfigChanged (void) { return configChanged; }
+ virtual bool getInstChanged (void) { return instChanged; }
+ inline void setAllChanged (void)
+ {
+ configChanged = true;
+ instChanged = true;
+ }
+
+ inline void resourceDestroy (void) {
+ destroyTime = uint64_t (qpid::sys::Duration (qpid::sys::now ()));
+ deleted = true;
+ }
+ bool isDeleted (void) { return deleted; }
+
+};
+
+typedef std::map<uint64_t,ManagementObject::shared_ptr> ManagementObjectMap;
+
+}}
+
+
+
+#endif /*!_ManagementObject_*/
diff --git a/qpid/cpp/src/qpid/memory.h b/qpid/cpp/src/qpid/memory.h
new file mode 100644
index 0000000000..99d7a71e7b
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/pointer_to_other.h b/qpid/cpp/src/qpid/pointer_to_other.h
new file mode 100644
index 0000000000..a99dc89658
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/ptr_map.h b/qpid/cpp/src/qpid/ptr_map.h
new file mode 100644
index 0000000000..e9a1d507a6
--- /dev/null
+++ b/qpid/cpp/src/qpid/ptr_map.h
@@ -0,0 +1,120 @@
+#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/version.hpp>
+
+namespace qpid {
+namespace ptr_map {
+
+/** @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 get_pointer(i) to get the pointer from
+ * a boost::ptr_map iterator.
+ *
+ * Can be removed when we no longer support platforms on 1.33.
+ *
+ * @see http://www.boost.org/libs/ptr_container/doc/ptr_container.html#upgrading-from-boost-v-1-33
+ */
+
+#include <boost/type_traits/remove_const.hpp>
+
+#if (BOOST_VERSION < 103400)
+
+template <class PtrMapIter>
+typename PtrMapIter::pointer get_pointer(const PtrMapIter& i)
+{ return &*i; }
+
+#else
+
+template <class PtrMapIter>
+typename boost::remove_const<typename PtrMapIter::value_type::second_type>::type
+get_pointer(const PtrMapIter& i)
+{ return i->second; }
+
+#endif
+
+}} // namespace qpid::ptr_map
+
+#endif /*!QPID_PTR_MAP*/
+#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/version.hpp>
+
+namespace qpid {
+namespace ptr_map {
+
+/** @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 get_pointer(i) to get the pointer from
+ * a boost::ptr_map iterator.
+ *
+ * Can be removed when we no longer support platforms on 1.33.
+ *
+ * @see http://www.boost.org/libs/ptr_container/doc/ptr_container.html#upgrading-from-boost-v-1-33
+ */
+#if (BOOST_VERSION < 103400)
+
+template <class PtrMapIter>
+typename PtrMapIter::pointer get_pointer(const PtrMapIter& i)
+{ return &*i; }
+
+#else
+
+template <class PtrMapIter>
+typename PtrMapIter::value_type::second_type get_pointer(const PtrMapIter& i)
+{ return i->second; }
+
+#endif
+
+}} // namespace qpid::ptr_map
+
+#endif /*!QPID_PTR_MAP*/
diff --git a/qpid/cpp/src/qpid/shared_ptr.h b/qpid/cpp/src/qpid/shared_ptr.h
new file mode 100644
index 0000000000..0c933ea6a6
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/sys/Acceptor.h b/qpid/cpp/src/qpid/sys/Acceptor.h
new file mode 100644
index 0000000000..1e7827e60c
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/Acceptor.h
@@ -0,0 +1,53 @@
+#ifndef _sys_Acceptor_h
+#define _sys_Acceptor_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>
+#include "qpid/SharedObject.h"
+#include "ConnectionCodec.h"
+
+namespace qpid {
+namespace sys {
+
+class Acceptor : public qpid::SharedObject<Acceptor>
+{
+ public:
+ static Acceptor::shared_ptr create(int16_t port, int backlog, int threads);
+ virtual ~Acceptor() = 0;
+ virtual uint16_t getPort() const = 0;
+ virtual std::string getHost() const = 0;
+ virtual void run(ConnectionCodec::Factory*) = 0;
+ virtual void connect(
+ const std::string& host, int16_t port, ConnectionCodec::Factory* codec) = 0;
+
+ /** Note: this function is async-signal safe */
+ virtual void shutdown() = 0;
+};
+
+inline Acceptor::~Acceptor() {}
+
+}}
+
+
+
+#endif /*!_sys_Acceptor_h*/
diff --git a/qpid/cpp/src/qpid/sys/AggregateOutput.cpp b/qpid/cpp/src/qpid/sys/AggregateOutput.cpp
new file mode 100644
index 0000000000..57cc0c5a33
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/AggregateOutput.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/sys/AggregateOutput.h"
+#include "qpid/log/Statement.h"
+#include <algorithm>
+
+namespace qpid {
+namespace sys {
+
+void AggregateOutput::activateOutput()
+{
+ control.activateOutput();
+}
+
+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 (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);
+}
+
+}} // namespace qpid::sys
diff --git a/qpid/cpp/src/qpid/sys/AggregateOutput.h b/qpid/cpp/src/qpid/sys/AggregateOutput.h
new file mode 100644
index 0000000000..a870fcb95a
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/AggregateOutput.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 _AggregateOutput_
+#define _AggregateOutput_
+
+#include <vector>
+#include "Mutex.h"
+#include "OutputControl.h"
+#include "OutputTask.h"
+
+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();
+ //all the following will be called on the same thread
+ bool doOutput();
+ void addOutputTask(OutputTask* t);
+ void removeOutputTask(OutputTask* t);
+ };
+
+}
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/sys/AsynchIO.h b/qpid/cpp/src/qpid/sys/AsynchIO.h
new file mode 100644
index 0000000000..ca34d82741
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/AsynchIO.h
@@ -0,0 +1,134 @@
+#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.
+ *
+ */
+
+#include "Dispatcher.h"
+
+#include <boost/function.hpp>
+#include <deque>
+
+namespace qpid {
+namespace sys {
+
+/*
+ * Asynchronous acceptor: accepts connections then does a callback with the
+ * accepted fd
+ */
+class AsynchAcceptor {
+public:
+ typedef boost::function1<void, const Socket&> Callback;
+
+private:
+ Callback acceptedCallback;
+ DispatchHandle handle;
+
+public:
+ AsynchAcceptor(const Socket& s, Callback callback);
+ void start(Poller::shared_ptr poller);
+
+private:
+ void readable(DispatchHandle& handle);
+};
+
+/*
+ * Asycnchronous 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 AsynchIO : private DispatchHandle {
+public:
+ struct BufferBase {
+ char* const bytes;
+ const int32_t byteCount;
+ int32_t dataStart;
+ int32_t dataCount;
+
+ BufferBase(char* const b, const int32_t s) :
+ bytes(b),
+ byteCount(s),
+ dataStart(0),
+ dataCount(0)
+ {}
+
+ virtual ~BufferBase()
+ {}
+ };
+
+ typedef boost::function2<void, 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;
+
+private:
+ ReadCallback readCallback;
+ EofCallback eofCallback;
+ DisconnectCallback disCallback;
+ ClosedCallback closedCallback;
+ BuffersEmptyCallback emptyCallback;
+ IdleCallback idleCallback;
+ 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:
+ AsynchIO(const Socket& s,
+ ReadCallback rCb, EofCallback eofCb, DisconnectCallback disCb,
+ ClosedCallback cCb = 0, BuffersEmptyCallback eCb = 0, IdleCallback iCb = 0);
+ void queueForDeletion();
+
+ void start(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();
+ const Socket& getSocket() const { return DispatchHandle::getSocket(); }
+
+private:
+ ~AsynchIO();
+ void readable(DispatchHandle& handle);
+ void writeable(DispatchHandle& handle);
+ void disconnected(DispatchHandle& handle);
+ void close(DispatchHandle& handle);
+};
+
+}}
+
+#endif // _sys_AsynchIO
diff --git a/qpid/cpp/src/qpid/sys/AsynchIOAcceptor.cpp b/qpid/cpp/src/qpid/sys/AsynchIOAcceptor.cpp
new file mode 100644
index 0000000000..153557c5e5
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/AsynchIOAcceptor.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 "Acceptor.h"
+
+#include "Socket.h"
+#include "AsynchIO.h"
+#include "Mutex.h"
+#include "Thread.h"
+
+#include "qpid/sys/ConnectionOutputHandler.h"
+#include "qpid/framing/AMQP_HighestVersion.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/framing/ProtocolInitiation.h"
+#include "qpid/log/Statement.h"
+
+#include <boost/bind.hpp>
+#include <boost/assert.hpp>
+#include <queue>
+#include <vector>
+#include <memory>
+#include <ostream>
+
+namespace qpid {
+namespace sys {
+
+class AsynchIOAcceptor : public Acceptor {
+ Poller::shared_ptr poller;
+ Socket listener;
+ int numIOThreads;
+ const uint16_t listeningPort;
+
+ public:
+ AsynchIOAcceptor(int16_t port, int backlog, int threads);
+ ~AsynchIOAcceptor() {}
+ void run(ConnectionCodec::Factory*);
+ void connect(const std::string& host, int16_t port, ConnectionCodec::Factory*);
+
+ void shutdown();
+
+ uint16_t getPort() const;
+ std::string getHost() const;
+
+ private:
+ void accepted(Poller::shared_ptr, const Socket&, ConnectionCodec::Factory*);
+};
+
+Acceptor::shared_ptr Acceptor::create(int16_t port, int backlog, int threads)
+{
+ return Acceptor::shared_ptr(new AsynchIOAcceptor(port, backlog, threads));
+}
+
+AsynchIOAcceptor::AsynchIOAcceptor(int16_t port, int backlog, int threads) :
+ poller(new Poller),
+ numIOThreads(threads),
+ listeningPort(listener.listen(port, backlog))
+{}
+
+// Buffer definition
+struct Buff : public AsynchIO::BufferBase {
+ Buff() :
+ AsynchIO::BufferBase(new char[65536], 65536)
+ {}
+ ~Buff()
+ { delete [] bytes;}
+};
+
+class AsynchIOHandler : public OutputControl {
+ AsynchIO* aio;
+ ConnectionCodec::Factory* factory;
+ ConnectionCodec* codec;
+ bool readError;
+ std::string identifier;
+ bool isClient;
+
+ void write(const framing::ProtocolInitiation&);
+
+ public:
+ AsynchIOHandler() :
+ aio(0),
+ factory(0),
+ codec(0),
+ readError(false),
+ isClient(false)
+ {}
+
+ ~AsynchIOHandler() {
+ if (codec)
+ codec->closed();
+ delete codec;
+ }
+
+ void setClient() { isClient = true; }
+
+ void init(AsynchIO* a, ConnectionCodec::Factory* f) {
+ aio = a;
+ factory = f;
+ identifier = aio->getSocket().getPeerAddress();
+
+ }
+
+ // Output side
+ void close();
+ void activateOutput();
+
+ // Input side
+ void readbuff(AsynchIO& aio, AsynchIO::BufferBase* 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);
+};
+
+void AsynchIOAcceptor::accepted(Poller::shared_ptr poller, const Socket& s, ConnectionCodec::Factory* f) {
+ AsynchIOHandler* async = new AsynchIOHandler;
+ AsynchIO* aio = new AsynchIO(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, f);
+ // Give connection some buffers to use
+ for (int i = 0; i < 4; i++) {
+ aio->queueReadBuffer(new Buff);
+ }
+ aio->start(poller);
+}
+
+
+uint16_t AsynchIOAcceptor::getPort() const {
+ return listeningPort; // Immutable no need for lock.
+}
+
+std::string AsynchIOAcceptor::getHost() const {
+ return listener.getSockname();
+}
+
+void AsynchIOAcceptor::run(ConnectionCodec::Factory* fact) {
+ Dispatcher d(poller);
+ AsynchAcceptor
+ acceptor(listener,
+ boost::bind(&AsynchIOAcceptor::accepted, this, poller, _1, fact));
+ acceptor.start(poller);
+
+ 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 AsynchIOAcceptor::connect(
+ const std::string& host, int16_t port, ConnectionCodec::Factory* f)
+{
+ Socket* socket = new Socket();//Should be deleted by handle when socket closes
+ socket->connect(host, port);
+ AsynchIOHandler* async = new AsynchIOHandler;
+ async->setClient();
+ AsynchIO* aio = new AsynchIO(*socket,
+ 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, f);
+ // Give connection some buffers to use
+ for (int i = 0; i < 4; i++) {
+ aio->queueReadBuffer(new Buff);
+ }
+ aio->start(poller);
+}
+
+
+void AsynchIOAcceptor::shutdown() {
+ // NB: this function must be async-signal safe, it must not
+ // call any function that is not async-signal safe.
+ poller->shutdown();
+}
+
+
+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.size();
+ aio->queueWrite(buff);
+}
+
+void AsynchIOHandler::activateOutput() {
+ aio->notifyPendingWrite();
+}
+
+// Input side
+void AsynchIOHandler::readbuff(AsynchIO& , AsynchIO::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 << ")");
+ 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();
+ }
+ }
+ }
+ // 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 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/qpid/cpp/src/qpid/sys/AtomicCount.h b/qpid/cpp/src/qpid/sys/AtomicCount.h
new file mode 100644
index 0000000000..54081092c8
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/AtomicCount.h
@@ -0,0 +1,53 @@
+#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/qpid/cpp/src/qpid/sys/BlockingQueue.h b/qpid/cpp/src/qpid/sys/BlockingQueue.h
new file mode 100644
index 0000000000..dd709c6bff
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/BlockingQueue.h
@@ -0,0 +1,142 @@
+#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 lock;
+ std::queue<T> queue;
+ bool closed;
+
+public:
+ BlockingQueue() : closed(false) {}
+ ~BlockingQueue() { close(); }
+
+ /** Block until there is a value to pop */
+ T pop()
+ {
+ Waitable::ScopedLock l(lock);
+ if (!queueWait()) throw ClosedException();
+ return popInternal();
+ }
+
+ /** Non-blocking pop. If there is a value set outValue and return
+ * true, else return false;
+ */
+ bool tryPop(T& outValue) {
+ Waitable::ScopedLock l(lock);
+ if (queue.empty()) return false;
+ outValue = popInternal();
+ return true;
+ }
+
+ /** Non-blocking pop. If there is a value return it, else return
+ * valueIfEmpty.
+ */
+ T tryPop(const T& valueIfEmpty=T()) {
+ T result=valueIfEmpty;
+ tryPop(result);
+ return result;
+ }
+
+ /** Push a value onto the queue */
+ void push(const T& t)
+ {
+ Waitable::ScopedLock l(lock);
+ queue.push(t);
+ queueNotify(0);
+ }
+
+ /**
+ * Close the queue. Throws ClosedException in threads waiting in pop().
+ * Blocks till all waiting threads have been notified.
+ */
+ void close()
+ {
+ Waitable::ScopedLock l(lock);
+ if (!closed) {
+ closed = true;
+ lock.notifyAll();
+ lock.waitWaiters(); // Ensure no threads are still waiting.
+ }
+ }
+
+ /** Open a closed queue. */
+ void open() {
+ Waitable::ScopedLock l(lock);
+ closed=false;
+ }
+
+ bool isClosed() const {
+ Waitable::ScopedLock l(lock);
+ return closed;
+ }
+
+ bool empty() const {
+ Waitable::ScopedLock l(lock);
+ return queue.empty();
+ }
+ size_t size() const {
+ Waitable::ScopedLock l(lock);
+ return queue.size();
+ }
+
+ private:
+
+ void queueNotify(size_t ignore) {
+ if (!queue.empty() && lock.hasWaiters()>ignore)
+ lock.notify(); // Notify another waiter.
+ }
+
+ bool queueWait() {
+ Waitable::ScopedWait w(lock);
+ while (!closed && queue.empty())
+ lock.wait();
+ return !queue.empty();
+ }
+
+ T popInternal() {
+ T t=queue.front();
+ queue.pop();
+ queueNotify(1);
+ return t;
+ }
+
+};
+
+}}
+
+
+
+#endif /*!QPID_SYS_BLOCKINGQUEUE_H*/
diff --git a/qpid/cpp/src/qpid/sys/Condition.h b/qpid/cpp/src/qpid/sys/Condition.h
new file mode 100644
index 0000000000..961c15e1ee
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/Condition.h
@@ -0,0 +1,31 @@
+#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"
+#else
+#include "posix/Condition.h"
+#endif
+
+#endif /*!_sys_Condition_h*/
diff --git a/qpid/cpp/src/qpid/sys/ConnectionCodec.h b/qpid/cpp/src/qpid/sys/ConnectionCodec.h
new file mode 100644
index 0000000000..205596c709
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/ConnectionCodec.h
@@ -0,0 +1,80 @@
+#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"
+#include "OutputControl.h"
+#include <memory>
+#include <map>
+
+namespace qpid {
+
+namespace broker { class Broker; }
+
+namespace sys {
+
+/**
+ * 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/qpid/cpp/src/qpid/sys/ConnectionInputHandler.h b/qpid/cpp/src/qpid/sys/ConnectionInputHandler.h
new file mode 100644
index 0000000000..a2c18d6d9a
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/ConnectionInputHandler.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 _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/qpid/cpp/src/qpid/sys/ConnectionInputHandlerFactory.h b/qpid/cpp/src/qpid/sys/ConnectionInputHandlerFactory.h
new file mode 100644
index 0000000000..2b309b5758
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/ConnectionInputHandlerFactory.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 _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) = 0;
+
+ virtual ~ConnectionInputHandlerFactory(){}
+};
+
+}}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/sys/ConnectionOutputHandler.h b/qpid/cpp/src/qpid/sys/ConnectionOutputHandler.h
new file mode 100644
index 0000000000..5a60ae4998
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/ConnectionOutputHandler.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.
+ *
+ */
+#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;
+};
+
+}}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/sys/DeletionManager.h b/qpid/cpp/src/qpid/sys/DeletionManager.h
new file mode 100644
index 0000000000..43154eb98e
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/sys/Dispatcher.cpp b/qpid/cpp/src/qpid/sys/Dispatcher.cpp
new file mode 100644
index 0000000000..c55f808b42
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/Dispatcher.cpp
@@ -0,0 +1,441 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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 <boost/cast.hpp>
+
+#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();
+ DispatchHandle* h =
+ boost::polymorphic_downcast<DispatchHandle*>(event.handle);
+
+ // If can read/write then dispatch appropriate callbacks
+ if (h) {
+ h->dispatchCallbacks(event.type);
+ } else {
+ // Handle shutdown
+ switch (event.type) {
+ case Poller::SHUTDOWN:
+ goto dispatcher_shutdown;
+ default:
+ // This should be impossible
+ assert(false);
+ }
+ }
+ } while (true);
+
+dispatcher_shutdown:
+ ;
+}
+
+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::IN) :
+ Poller::OUT;
+
+ 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::IN) :
+ Poller::OUT;
+ 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::IN);
+ 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::OUT);
+ 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::OUT);
+ 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::IN);
+ 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
+ deferDelete();
+}
+
+void DispatchHandle::dispatchCallbacks(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::IN);
+ state = ACTIVE_R;
+ return;
+ case DELAYED_W:
+ poller->modFd(*this, Poller::OUT);
+ 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;
+ }
+ }
+ deferDelete();
+}
+
+}}
diff --git a/qpid/cpp/src/qpid/sys/Dispatcher.h b/qpid/cpp/src/qpid/sys/Dispatcher.h
new file mode 100644
index 0000000000..7cc4873068
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/Dispatcher.h
@@ -0,0 +1,96 @@
+#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"
+#include "Mutex.h"
+
+#include <memory>
+#include <queue>
+#include <boost/function.hpp>
+
+#include <assert.h>
+
+
+namespace qpid {
+namespace sys {
+
+class Dispatcher;
+class DispatchHandle : public PollerHandle {
+ friend class Dispatcher;
+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:
+ DispatchHandle(const Socket& s, Callback rCb, Callback wCb, Callback dCb) :
+ PollerHandle(s),
+ readableCallback(rCb),
+ writableCallback(wCb),
+ disconnectedCallback(dCb),
+ state(IDLE)
+ {}
+
+ ~DispatchHandle();
+
+ void startWatch(Poller::shared_ptr poller);
+ void rewatch();
+ void rewatchRead();
+ void rewatchWrite();
+ void unwatch();
+ void unwatchRead();
+ void unwatchWrite();
+ void stopWatch();
+
+protected:
+ void doDelete();
+
+private:
+ void dispatchCallbacks(Poller::EventType dir);
+};
+
+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/qpid/cpp/src/qpid/sys/Module.h b/qpid/cpp/src/qpid/sys/Module.h
new file mode 100644
index 0000000000..79793ed0ca
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/Module.h
@@ -0,0 +1,50 @@
+#ifndef QPID_SYS_MODULE_H
+#define QPID_SYS_MODULE_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/Shlib.h"
+#include <boost/noncopyable.hpp>
+
+namespace qpid {
+namespace sys {
+
+template <class T> class Module : public AutoShlib, private boost::noncopyable
+{
+ public:
+ Module(const std::string& name) :
+ AutoShlib(name),
+ ptr(getSymbol<T*(*)()>("create")()) {}
+
+ T* get() { return ptr; }
+ T* operator->() { return ptr; }
+ ~Module() throw() {
+ getSymbol<void (*)(T*)>("destroy")(ptr);
+ }
+
+ private:
+ T* ptr;
+};
+
+}}
+
+#endif /*!QPID_SYS_MODULE_H*/
diff --git a/qpid/cpp/src/qpid/sys/Monitor.h b/qpid/cpp/src/qpid/sys/Monitor.h
new file mode 100644
index 0000000000..1d9835675c
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/Monitor.h
@@ -0,0 +1,51 @@
+#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 <sys/errno.h>
+#include "Condition.h"
+
+namespace qpid {
+namespace sys {
+
+/**
+ * A monitor is a condition variable and a mutex
+ */
+class Monitor : public Mutex, public Condition {
+ public:
+ using Condition::wait;
+ 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/qpid/cpp/src/qpid/sys/Mutex.h b/qpid/cpp/src/qpid/sys/Mutex.h
new file mode 100644
index 0000000000..b4bd3a9b4a
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/Mutex.h
@@ -0,0 +1,89 @@
+#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"
+#else
+#include "posix/Mutex.h"
+#endif
+
+#endif /*!_sys_Mutex_h*/
diff --git a/qpid/cpp/src/qpid/sys/OutputControl.h b/qpid/cpp/src/qpid/sys/OutputControl.h
new file mode 100644
index 0000000000..d922a0d85c
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/OutputControl.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 _OutputControl_
+#define _OutputControl_
+
+namespace qpid {
+namespace sys {
+
+ class OutputControl
+ {
+ public:
+ virtual ~OutputControl() {}
+ virtual void activateOutput() = 0;
+ };
+
+}
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/sys/OutputTask.h b/qpid/cpp/src/qpid/sys/OutputTask.h
new file mode 100644
index 0000000000..109765b8c3
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/OutputTask.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 _OutputTask_
+#define _OutputTask_
+
+namespace qpid {
+namespace sys {
+
+ class OutputTask
+ {
+ public:
+ virtual ~OutputTask() {}
+ virtual bool doOutput() = 0;
+ };
+
+}
+}
+
+
+#endif
diff --git a/qpid/cpp/src/qpid/sys/Poller.h b/qpid/cpp/src/qpid/sys/Poller.h
new file mode 100644
index 0000000000..0d6b4f9308
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/Poller.h
@@ -0,0 +1,110 @@
+#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 "Socket.h"
+
+#include <stdint.h>
+
+#include <boost/shared_ptr.hpp>
+
+namespace qpid {
+namespace sys {
+
+/**
+ * Handle class to use for polling
+ */
+class Poller;
+class PollerHandlePrivate;
+class PollerHandle {
+ friend class Poller;
+
+ PollerHandlePrivate* const impl;
+ const Socket& socket;
+
+public:
+ PollerHandle(const Socket& s);
+
+ // Usual way to delete (will defer deletion until we
+ // can't be returned from a Poller::wait any more)
+ void deferDelete();
+
+ // Class clients shouldn't ever use this
+ virtual ~PollerHandle();
+
+ const Socket& getSocket() const {return socket;}
+};
+
+/**
+ * Poller: abstract class to encapsulate a file descriptor poll to be used
+ * by a reactor
+ */
+class PollerPrivate;
+class Poller {
+ PollerPrivate* const impl;
+
+public:
+ typedef boost::shared_ptr<Poller> shared_ptr;
+
+ enum Direction {
+ NONE = 0,
+ IN,
+ OUT,
+ 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) {
+ }
+ };
+
+ 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);
+};
+
+}}
+#endif // _sys_Poller_h
diff --git a/qpid/cpp/src/qpid/sys/Runnable.cpp b/qpid/cpp/src/qpid/sys/Runnable.cpp
new file mode 100644
index 0000000000..30122c682f
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/sys/Runnable.h b/qpid/cpp/src/qpid/sys/Runnable.h
new file mode 100644
index 0000000000..fb3927c612
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/sys/ScopedIncrement.h b/qpid/cpp/src/qpid/sys/ScopedIncrement.h
new file mode 100644
index 0000000000..8645ab2484
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/sys/Semaphore.h b/qpid/cpp/src/qpid/sys/Semaphore.h
new file mode 100644
index 0000000000..3efb7ce2df
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/sys/Serializer.cpp b/qpid/cpp/src/qpid/sys/Serializer.cpp
new file mode 100644
index 0000000000..86f901aa78
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/Serializer.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 "qpid/sys/Serializer.h"
+#include "qpid/log/Statement.h"
+
+#include <boost/bind.hpp>
+
+#include <assert.h>
+
+namespace qpid {
+namespace sys {
+
+SerializerBase::SerializerBase(bool allowImmediate)
+ : state(IDLE), immediate(allowImmediate) {}
+
+void SerializerBase::shutdown() {
+ {
+ Mutex::ScopedLock l(lock);
+ if (state == SHUTDOWN) return;
+ state = SHUTDOWN;
+ lock.notify();
+ }
+ if (worker.id() != 0)
+ worker.join();
+}
+
+void SerializerBase::notifyWorker() {
+ // Call with lock held.
+ if (!worker.id())
+ worker = Thread(*this);
+ else
+ lock.notify();
+}
+
+bool SerializerBase::running() {
+ Mutex::ScopedLock l(lock);
+ return state != SHUTDOWN;
+}
+
+void SerializerBase::wait() {
+ Mutex::ScopedLock l(lock);
+ if (state == IDLE) lock.wait();
+}
+
+void SerializerBase::run() {
+ while (running()) {
+ dispatch();
+ wait();
+ }
+}
+
+}} // namespace qpid::sys
diff --git a/qpid/cpp/src/qpid/sys/Serializer.h b/qpid/cpp/src/qpid/sys/Serializer.h
new file mode 100644
index 0000000000..fe4afc85cb
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/Serializer.h
@@ -0,0 +1,181 @@
+#ifndef SERIALIZER_H
+#define 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 "qpid/Exception.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/sys/Monitor.h"
+#include "qpid/sys/Thread.h"
+
+#include <boost/function.hpp>
+#include <boost/noncopyable.hpp>
+
+#include <deque>
+
+namespace qpid {
+namespace sys {
+
+/** Abstract base class for Serializer below. */
+class SerializerBase : private boost::noncopyable, private Runnable
+{
+ public:
+ typedef boost::function<void()> VoidFn0;
+ struct ShutdownException : public Exception {};
+
+ /** @see Serializer::Serializer */
+ SerializerBase(bool immediate=true);
+
+ virtual ~SerializerBase() { shutdown(); }
+
+ virtual void dispatch() = 0;
+ protected:
+ enum State {
+ IDLE, ///< No threads are active.
+ EXECUTING, ///< execute() is executing a single task.
+ DISPATCHING, ///< dispatch() is draining the queue.
+ SHUTDOWN ///< SerailizerBase is being destroyed.
+ };
+
+ void shutdown();
+ void notifyWorker();
+ void run();
+ virtual bool empty() = 0;
+ bool running();
+ void wait();
+
+ Monitor lock;
+ State state;
+ bool immediate;
+ Thread worker;
+};
+
+
+/**
+ * Execute tasks sequentially, queuing tasks when necessary to
+ * ensure only one thread at a time executes a task and tasks
+ * are executed in order.
+ *
+ * Task is a void returning 0-arg functor. It must not throw exceptions.
+ *
+ * Note we deliberately do not use boost::function as the task type
+ * because copying a boost::functor allocates the target object on the
+ * heap.
+ */
+template <class Task>
+class Serializer : public SerializerBase {
+
+ std::deque<Task> queue;
+
+ bool empty() { return queue.empty(); }
+ void dispatch(Task& task);
+
+ public:
+ /** Start a serializer.
+ *
+ * @param immediate Allow execute() to execute a task immediatly
+ * in the current thread.
+ */
+ Serializer(bool immediate=true)
+ : SerializerBase(immediate) {}
+
+ ~Serializer() { shutdown(); }
+ /**
+ * Task may be executed immediately in the calling thread if there
+ * are no other tasks pending or executing and the "immediate"
+ * paramater to the constructor was true. Otherwise task will be
+ * enqueued for execution by a dispatch thread.
+ */
+ void execute(Task& task);
+
+
+ /** Execute pending tasks sequentially in calling thread.
+ * Drains the task queue and returns, does not block for more tasks.
+ *
+ * @exception ShutdownException if the serializer is being destroyed.
+ */
+ void dispatch();
+ };
+
+
+template <class Task>
+void Serializer<Task>::execute(Task& task) {
+ Mutex::ScopedLock l(lock);
+ assert(state != SHUTDOWN);
+ if (immediate && state == IDLE) {
+ state = EXECUTING;
+ dispatch(task);
+ if (state != SHUTDOWN) {
+ assert(state == EXECUTING);
+ state = IDLE;
+ }
+ }
+ else
+ queue.push_back(task);
+ if (!queue.empty() && state == IDLE) {
+ state = DISPATCHING;
+ notifyWorker();
+ }
+}
+
+template <class Task>
+void Serializer<Task>::dispatch() {
+ Mutex::ScopedLock l(lock);
+ // TODO aconway 2007-07-16: This loop could be unbounded
+ // if other threads add work while we're in dispatch(Task&).
+ // If we need to bound it we could dispatch just the elements
+ // that were enqueued when dispatch() was first called - save
+ // begin() iterator and pop only up to that.
+ while (!queue.empty() && state != SHUTDOWN) {
+ assert(state == DISPATCHING);
+ dispatch(queue.front());
+ queue.pop_front();
+ }
+ if (state != SHUTDOWN) {
+ assert(state == DISPATCHING);
+ state = IDLE;
+ }
+}
+
+template <class Task>
+void Serializer<Task>::dispatch(Task& task) {
+ // Preconditions: lock is held, state is EXECUTING or DISPATCHING
+ assert(state != IDLE);
+ assert(state != SHUTDOWN);
+ assert(state == EXECUTING || state == DISPATCHING);
+ Mutex::ScopedUnlock u(lock);
+ // No exceptions allowed in task.
+ notifyWorker();
+ try { task(); } catch (...) { assert(0); }
+}
+
+
+
+
+}} // namespace qpid::sys
+
+
+
+
+
+#endif /*!SERIALIZER_H*/
diff --git a/qpid/cpp/src/qpid/sys/Shlib.cpp b/qpid/cpp/src/qpid/sys/Shlib.cpp
new file mode 100644
index 0000000000..8fd3f42cc6
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/sys/Shlib.h b/qpid/cpp/src/qpid/sys/Shlib.h
new file mode 100644
index 0000000000..e2752dc7d6
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/Shlib.h
@@ -0,0 +1,76 @@
+#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>
+#include <dlfcn.h>
+
+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/qpid/cpp/src/qpid/sys/ShutdownHandler.h b/qpid/cpp/src/qpid/sys/ShutdownHandler.h
new file mode 100644
index 0000000000..88baecb5b6
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/sys/Socket.h b/qpid/cpp/src/qpid/sys/Socket.h
new file mode 100644
index 0000000000..0ebfc0c330
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/Socket.h
@@ -0,0 +1,116 @@
+#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 <string>
+#include "qpid/sys/Time.h"
+
+struct sockaddr;
+
+namespace qpid {
+namespace sys {
+
+class SocketPrivate;
+class Socket
+{
+ friend class Poller;
+
+ SocketPrivate* const impl;
+
+public:
+ /** Create a socket wrapper for descriptor. */
+ Socket();
+ ~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, int port) const;
+
+ void close() const;
+
+ enum { SOCKET_TIMEOUT=-2, SOCKET_EOF=-3 } ErrorCode;
+
+ /** Returns bytes sent or an ErrorCode value < 0. */
+ ssize_t send(const void* data, size_t size) const;
+
+ /**
+ * Returns bytes received, an ErrorCode value < 0 or 0
+ * if the connection closed in an orderly manner.
+ */
+ ssize_t recv(void* data, size_t size) 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(int 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;
+
+
+ /** 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;
+
+ int toFd() const;
+
+private:
+ Socket(SocketPrivate*);
+};
+
+}}
+#endif /*!_sys_Socket_h*/
diff --git a/qpid/cpp/src/qpid/sys/StateMonitor.h b/qpid/cpp/src/qpid/sys/StateMonitor.h
new file mode 100644
index 0000000000..5a92756f3a
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/sys/SystemInfo.cpp b/qpid/cpp/src/qpid/sys/SystemInfo.cpp
new file mode 100644
index 0000000000..dcc7ad9985
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/SystemInfo.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 "SystemInfo.h"
+#include <unistd.h>
+
+namespace qpid {
+namespace sys {
+
+long SystemInfo::concurrency() {
+#ifdef _SC_NPROCESSORS_ONLN // Linux specific.
+ return sysconf(_SC_NPROCESSORS_ONLN);
+#else
+ return -1;
+#endif
+}
+
+}} // namespace qpid::sys
diff --git a/qpid/cpp/src/qpid/sys/SystemInfo.h b/qpid/cpp/src/qpid/sys/SystemInfo.h
new file mode 100644
index 0000000000..73c3ca3c17
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/SystemInfo.h
@@ -0,0 +1,44 @@
+#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.
+ *
+ */
+
+namespace qpid {
+namespace sys {
+
+/**
+ * Retrieve information about the system we are running on.
+ * Results may be dependent on OS/hardware.
+ */
+class SystemInfo
+{
+ public:
+ /** Estimate available concurrency, e.g. number of CPU cores.
+ * -1 means estimate not available on this platform.
+ */
+ static long concurrency();
+};
+
+}} // namespace qpid::sys
+
+
+
+#endif /*!QPID_SYS_SYSTEMINFO_H*/
diff --git a/qpid/cpp/src/qpid/sys/Thread.h b/qpid/cpp/src/qpid/sys/Thread.h
new file mode 100644
index 0000000000..fd9be5617e
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/Thread.h
@@ -0,0 +1,31 @@
+#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.
+ *
+ */
+
+#ifdef USE_APR_PLATFORM
+#include "apr/Thread.h"
+#else
+#include "posix/Thread.h"
+#endif
+
+#endif /*!_sys_Thread_h*/
diff --git a/qpid/cpp/src/qpid/sys/Time.h b/qpid/cpp/src/qpid/sys/Time.h
new file mode 100644
index 0000000000..6501cd0806
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/Time.h
@@ -0,0 +1,154 @@
+#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 <stdint.h>
+#include <limits>
+#include <iosfwd>
+
+namespace qpid {
+namespace sys {
+
+class Duration;
+
+/** 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,i
+ * 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 {
+ static int64_t max() { return std::numeric_limits<int64_t>::max(); }
+ int64_t time_ns;
+
+ friend class Duration;
+
+public:
+ inline AbsTime() {}
+ inline AbsTime(const AbsTime& time0, const Duration& duration);
+ // Default assignment operation fine
+ // Default copy constructor fine
+
+ static AbsTime now();
+ inline static AbsTime FarFuture();
+ bool operator==(const AbsTime& t) const { return t.time_ns == time_ns; }
+ template <class S> void serialize(S& s) { s(time_ns); }
+
+ 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 to represent the duration between instants of time:
+ * As AbsTime this class also uses nanosecs for its time
+ * resolution. 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 conveient.
+ */
+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);
+ inline explicit Duration(const AbsTime& time0);
+ inline explicit Duration(const AbsTime& start, const AbsTime& finish);
+ inline operator int64_t() const;
+};
+
+std::ostream& operator << (std::ostream&, const Duration&);
+
+AbsTime::AbsTime(const AbsTime& t, const Duration& d) :
+ time_ns(d == Duration::max() ? max() : t.time_ns+d.nanosecs)
+{}
+
+AbsTime AbsTime::FarFuture() { AbsTime ff; ff.time_ns = max(); return ff;}
+
+inline AbsTime now() { return AbsTime::now(); }
+
+inline bool operator<(const AbsTime& a, const AbsTime& b) { return a.time_ns < b.time_ns; }
+inline bool operator>(const AbsTime& a, const AbsTime& b) { return a.time_ns > b.time_ns; }
+
+Duration::Duration(int64_t time0) :
+ nanosecs(time0)
+{}
+
+Duration::Duration(const AbsTime& time0) :
+ nanosecs(time0.time_ns)
+{}
+
+Duration::Duration(const AbsTime& start, const AbsTime& finish) :
+ nanosecs(finish.time_ns - start.time_ns)
+{}
+
+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();
+
+}}
+
+#endif /*!_sys_Time_h*/
diff --git a/qpid/cpp/src/qpid/sys/TimeoutHandler.h b/qpid/cpp/src/qpid/sys/TimeoutHandler.h
new file mode 100644
index 0000000000..0c10709bbf
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/sys/Waitable.h b/qpid/cpp/src/qpid/sys/Waitable.h
new file mode 100644
index 0000000000..37392ed761
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/Waitable.h
@@ -0,0 +1,71 @@
+#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 "Monitor.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.
+ */
+class Waitable : public Monitor {
+ public:
+ Waitable() : waiters(0) {}
+
+ /** Use this inside a scoped lock around the
+ * call to Monitor::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 ScopedWaits.
+ *@pre Must be called inside a ScopedLock but NOT a ScopedWait.
+ */
+ void waitWaiters() {
+ while (waiters != 0)
+ wait();
+ }
+
+ /** Returns the number of outstanding ScopedWaits.
+ * Must be called with the lock held.
+ */
+ size_t hasWaiters() { return waiters; }
+
+ private:
+ friend struct ScopedWait;
+ size_t waiters;
+};
+
+}} // namespace qpid::sys
+
+
+
+#endif /*!QPID_SYS_WAITABLE_H*/
diff --git a/qpid/cpp/src/qpid/sys/apr/APRBase.cpp b/qpid/cpp/src/qpid/sys/apr/APRBase.cpp
new file mode 100644
index 0000000000..724c489303
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/sys/apr/APRBase.h b/qpid/cpp/src/qpid/sys/apr/APRBase.h
new file mode 100644
index 0000000000..7b5644a129
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/sys/apr/APRPool.cpp b/qpid/cpp/src/qpid/sys/apr/APRPool.cpp
new file mode 100644
index 0000000000..e8b71f6e8a
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/sys/apr/APRPool.h b/qpid/cpp/src/qpid/sys/apr/APRPool.h
new file mode 100644
index 0000000000..da7661fcfa
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/sys/apr/Condition.h b/qpid/cpp/src/qpid/sys/apr/Condition.h
new file mode 100644
index 0000000000..5e544219ab
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/sys/apr/Mutex.h b/qpid/cpp/src/qpid/sys/apr/Mutex.h
new file mode 100644
index 0000000000..51089c98ff
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/sys/apr/Shlib.cpp b/qpid/cpp/src/qpid/sys/apr/Shlib.cpp
new file mode 100644
index 0000000000..b0ba706713
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/sys/apr/Socket.cpp b/qpid/cpp/src/qpid/sys/apr/Socket.cpp
new file mode 100644
index 0000000000..577268844a
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/sys/apr/Thread.cpp b/qpid/cpp/src/qpid/sys/apr/Thread.cpp
new file mode 100644
index 0000000000..3369ef7eb1
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/sys/apr/Thread.h b/qpid/cpp/src/qpid/sys/apr/Thread.h
new file mode 100644
index 0000000000..8cbbc0456e
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/sys/apr/Time.cpp b/qpid/cpp/src/qpid/sys/apr/Time.cpp
new file mode 100644
index 0000000000..34e740b144
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/sys/epoll/EpollPoller.cpp b/qpid/cpp/src/qpid/sys/epoll/EpollPoller.cpp
new file mode 100644
index 0000000000..8936251f94
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/epoll/EpollPoller.cpp
@@ -0,0 +1,338 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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 "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<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
+ };
+
+ ::__uint32_t events;
+ FDStat stat;
+ Mutex lock;
+
+ PollerHandlePrivate() :
+ 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 Socket& s) :
+ impl(new PollerHandlePrivate),
+ socket(s)
+{}
+
+PollerHandle::~PollerHandle() {
+ delete impl;
+}
+
+void PollerHandle::deferDelete() {
+ PollerHandleDeletionManager.markForDeletion(this);
+}
+
+/**
+ * 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::IN: return ::EPOLLIN;
+ case Poller::OUT: 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.ptr = &handle;
+
+ QPID_POSIX_CHECK(::epoll_ctl(impl->epollFd, op, toFd(handle.socket.impl), &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, toFd(handle.socket.impl), 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.ptr = &handle;
+
+ QPID_POSIX_CHECK(::epoll_ctl(impl->epollFd, EPOLL_CTL_MOD, toFd(handle.socket.impl), &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.ptr = &handle;
+
+ QPID_POSIX_CHECK(::epoll_ctl(impl->epollFd, EPOLL_CTL_MOD, toFd(handle.socket.impl), &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.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) {
+ return Event(0, SHUTDOWN);
+ }
+
+ if (rc ==-1 && errno != EINTR) {
+ QPID_POSIX_CHECK(rc);
+ } else if (rc > 0) {
+ assert(rc == 1);
+ PollerHandle* handle = static_cast<PollerHandle*>(epe.data.ptr);
+ PollerHandlePrivate& eh = *handle->impl;
+
+ ScopedLock<Mutex> l(eh.lock);
+
+ // the handle could have gone inactive since we left the epoll_wait
+ if (eh.isActive()) {
+ // 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));
+ }
+ }
+ // 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) {
+ return Event(0, TIMEOUT);
+ }
+ } while (true);
+}
+
+// Concrete constructors
+Poller::Poller() :
+ impl(new PollerPrivate())
+{}
+
+Poller::~Poller() {
+ delete impl;
+}
+
+}}
diff --git a/qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp b/qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp
new file mode 100644
index 0000000000..94c68bd5d0
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp
@@ -0,0 +1,364 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/Time.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 <boost/bind.hpp>
+
+using namespace qpid::sys;
+
+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
+ */
+
+AsynchAcceptor::AsynchAcceptor(const Socket& s, Callback callback) :
+ acceptedCallback(callback),
+ handle(s, boost::bind(&AsynchAcceptor::readable, this, _1), 0, 0) {
+
+ s.setNonblocking();
+ ignoreSigpipe();
+}
+
+void AsynchAcceptor::start(Poller::shared_ptr poller) {
+ handle.startWatch(poller);
+}
+
+/*
+ * We keep on accepting as long as there is something to accept
+ */
+void AsynchAcceptor::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.
+ s = h.getSocket().accept(0, 0);
+ if (s) {
+ acceptedCallback(*s);
+ } else {
+ break;
+ }
+ } while (true);
+
+ h.rewatch();
+}
+
+/*
+ * Asynch reader/writer
+ */
+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),
+ 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();
+}
+
+/** 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 = h.getSocket().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 {
+ QPID_POSIX_CHECK(rc);
+ }
+ }
+ } 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 = h.getSocket().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();
+ h.getSocket().close();
+ if (closedCallback) {
+ closedCallback(*this, getSocket());
+ }
+}
+
diff --git a/qpid/cpp/src/qpid/sys/posix/Condition.h b/qpid/cpp/src/qpid/sys/posix/Condition.h
new file mode 100644
index 0000000000..86d6500ee9
--- /dev/null
+++ b/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/qpid/cpp/src/qpid/sys/posix/Mutex.h b/qpid/cpp/src/qpid/sys/posix/Mutex.h
new file mode 100644
index 0000000000..ceb2794abe
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/posix/Mutex.h
@@ -0,0 +1,201 @@
+#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;
+
+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;
+};
+
+
+/**
+ * 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_rwlockattr_t rwlockattr;
+ pthread_mutexattr_t mutexattr;
+
+ void initMutexattr() {
+ pthread_mutexattr_init(&mutexattr);
+ pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);
+ }
+
+ void initRWlockattr() {
+ pthread_rwlockattr_init(&rwlockattr);
+ }
+
+ struct RecursiveMutexattr {
+ RecursiveMutexattr() {
+ pthread_once(&onceControl, initMutexattr);
+ }
+
+ operator const pthread_mutexattr_t*() const {
+ return &mutexattr;
+ }
+ };
+ struct RecursiveRWlockattr {
+ RecursiveRWlockattr() {
+ pthread_once(&onceControl, initRWlockattr);
+ }
+
+ operator const pthread_rwlockattr_t*() const {
+ return &rwlockattr;
+ }
+ };
+
+ RecursiveMutexattr recursiveMutexattr;
+ RecursiveRWlockattr recursiveRWlockattr;
+
+
+
+}
+
+/**
+ * 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, recursiveMutexattr));
+}
+
+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, recursiveRWlockattr));
+}
+
+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/qpid/cpp/src/qpid/sys/posix/PrivatePosix.h b/qpid/cpp/src/qpid/sys/posix/PrivatePosix.h
new file mode 100644
index 0000000000..9ec9770cab
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/posix/PrivatePosix.h
@@ -0,0 +1,44 @@
+#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 socket related implementation details
+class SocketPrivate;
+int toFd(const SocketPrivate* s);
+
+}}
+
+#endif /*!_sys_posix_PrivatePosix_h*/
diff --git a/qpid/cpp/src/qpid/sys/posix/Shlib.cpp b/qpid/cpp/src/qpid/sys/posix/Shlib.cpp
new file mode 100644
index 0000000000..1552aa06b5
--- /dev/null
+++ b/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));
+ }
+}
+
+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));
+ return sym;
+}
+
+}} // namespace qpid::sys
diff --git a/qpid/cpp/src/qpid/sys/posix/Socket.cpp b/qpid/cpp/src/qpid/sys/posix/Socket.cpp
new file mode 100644
index 0000000000..c286ebce27
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/posix/Socket.cpp
@@ -0,0 +1,283 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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 <netdb.h>
+#include <cstdlib>
+#include <string.h>
+
+#include <boost/format.hpp>
+
+namespace qpid {
+namespace sys {
+
+class SocketPrivate {
+public:
+ SocketPrivate(int f = -1) :
+ fd(f)
+ {}
+
+ int fd;
+
+ std::string getName(bool local, bool includeService = false) const;
+ std::string getService(bool local) const;
+};
+
+std::string SocketPrivate::getName(bool local, bool includeService) const
+{
+ ::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 SocketPrivate::getService(bool local) const
+{
+ ::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() :
+ impl(new SocketPrivate)
+{
+ createTcp();
+}
+
+Socket::Socket(SocketPrivate* sp) :
+ impl(sp)
+{}
+
+Socket::~Socket() {
+ delete impl;
+}
+
+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, int port) const
+{
+ 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)
+ 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;
+}
+
+ssize_t
+Socket::send(const void* data, size_t size) const
+{
+ const int& socket = impl->fd;
+ ssize_t sent = ::send(socket, data, size, 0);
+ if (sent < 0) {
+ if (errno == ECONNRESET) return SOCKET_EOF;
+ if (errno == ETIMEDOUT) return SOCKET_TIMEOUT;
+ throw QPID_POSIX_ERROR(errno);
+ }
+ return sent;
+}
+
+ssize_t
+Socket::recv(void* data, size_t size) const
+{
+ const int& socket = impl->fd;
+ ssize_t received = ::recv(socket, data, size, 0);
+ if (received < 0) {
+ if (errno == ETIMEDOUT) return SOCKET_TIMEOUT;
+ throw QPID_POSIX_ERROR(errno);
+ }
+ return received;
+}
+
+int Socket::listen(int 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 QPID_POSIX_ERROR(errno);
+ if (::listen(socket, backlog) < 0)
+ throw QPID_POSIX_ERROR(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 SocketPrivate(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 impl->getName(true);
+}
+
+std::string Socket::getPeername() const
+{
+ return impl->getName(false);
+}
+
+std::string Socket::getPeerAddress() const
+{
+ return impl->getName(false, true);
+}
+
+std::string Socket::getLocalAddress() const
+{
+ return impl->getName(true, true);
+}
+
+uint16_t Socket::getLocalPort() const
+{
+ return atoi(impl->getService(true).c_str());
+}
+
+uint16_t Socket::getRemotePort() const
+{
+ return atoi(impl->getService(true).c_str());
+}
+
+int Socket::toFd() const {
+ return impl->fd;
+}
+
+int toFd(const SocketPrivate* s)
+{
+ return s->fd;
+}
+
+}} // namespace qpid::sys
diff --git a/qpid/cpp/src/qpid/sys/posix/Thread.cpp b/qpid/cpp/src/qpid/sys/posix/Thread.cpp
new file mode 100644
index 0000000000..dc9b21448f
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/posix/Thread.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 "Thread.h"
+#include "qpid/sys/Runnable.h"
+
+void* qpid::sys::Thread::runRunnable(void* p)
+{
+ static_cast<Runnable*>(p)->run();
+ return 0;
+}
diff --git a/qpid/cpp/src/qpid/sys/posix/Thread.h b/qpid/cpp/src/qpid/sys/posix/Thread.h
new file mode 100644
index 0000000000..7d51ec73aa
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/posix/Thread.h
@@ -0,0 +1,92 @@
+#ifndef _sys_posix_Thread_h
+#define _sys_posix_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 "check.h"
+#include <pthread.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
+ */
+ static unsigned long logId() { return current().id(); }
+
+ inline static void yield();
+
+ inline Thread();
+ inline explicit Thread(qpid::sys::Runnable*);
+ inline explicit Thread(qpid::sys::Runnable&);
+
+ inline void join();
+
+ inline unsigned long id();
+
+ private:
+ static void* runRunnable(void* runnable);
+ inline Thread(pthread_t);
+ pthread_t thread;
+};
+
+
+Thread::Thread() : thread(0) {}
+
+Thread::Thread(Runnable* runnable) {
+ QPID_POSIX_ASSERT_THROW_IF(pthread_create(&thread, NULL, runRunnable, runnable));
+}
+
+Thread::Thread(Runnable& runnable) {
+ QPID_POSIX_ASSERT_THROW_IF(pthread_create(&thread, NULL, runRunnable, &runnable));
+}
+
+void Thread::join(){
+ if (thread != 0)
+ QPID_POSIX_ASSERT_THROW_IF(pthread_join(thread, 0));
+}
+
+unsigned long Thread::id() {
+ return thread;
+}
+
+Thread::Thread(pthread_t thr) : thread(thr) {}
+
+Thread Thread::current() {
+ return Thread(pthread_self());
+}
+
+void Thread::yield()
+{
+ QPID_POSIX_ASSERT_THROW_IF(pthread_yield());
+}
+
+
+}}
+#endif /*!_sys_posix_Thread_h*/
diff --git a/qpid/cpp/src/qpid/sys/posix/Time.cpp b/qpid/cpp/src/qpid/sys/posix/Time.cpp
new file mode 100644
index 0000000000..09627cdc6b
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/posix/Time.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 "PrivatePosix.h"
+
+#include "qpid/sys/Time.h"
+#include <ostream>
+#include <time.h>
+#include <sys/time.h>
+
+namespace qpid {
+namespace sys {
+
+AbsTime AbsTime::now() {
+ struct timespec ts;
+ ::clock_gettime(CLOCK_REALTIME, &ts);
+ AbsTime time_now;
+ time_now.time_ns = toTime(ts).nanosecs;
+ return time_now;
+}
+
+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.time_ns/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;
+}
+
+}}
+
diff --git a/qpid/cpp/src/qpid/sys/posix/check.h b/qpid/cpp/src/qpid/sys/posix/check.h
new file mode 100644
index 0000000000..aa93c37205
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/posix/check.h
@@ -0,0 +1,47 @@
+#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>
+
+#define QPID_POSIX_ERROR(ERRNO) qpid::Exception(QPID_MSG(qpid::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/qpid/cpp/src/qpidd.cpp b/qpid/cpp/src/qpidd.cpp
new file mode 100644
index 0000000000..08b907cbe2
--- /dev/null
+++ b/qpid/cpp/src/qpidd.cpp
@@ -0,0 +1,260 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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"
+#include "qpid/sys/posix/check.h"
+#include "qpid/broker/Daemon.h"
+#include "qpid/log/Statement.h"
+#include "qpid/log/Options.h"
+#include "qpid/log/Logger.h"
+#include "qpid/Plugin.h"
+#include "qpid/sys/Shlib.h"
+#include "config.h"
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+#include <iostream>
+#include <fstream>
+#include <signal.h>
+#include <unistd.h>
+
+using namespace qpid;
+using namespace qpid::broker;
+using namespace qpid::sys;
+using namespace qpid::log;
+using namespace std;
+namespace fs=boost::filesystem;
+
+struct ModuleOptions : public qpid::Options {
+ string loadDir;
+ vector<string> load;
+ bool noLoad;
+ ModuleOptions() : qpid::Options("Module options"), loadDir("/usr/lib/qpidd"), noLoad(false)
+ {
+ addOptions()
+ ("module-dir", optValue(loadDir, "DIR"), "Load all .so 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");
+ }
+};
+
+
+struct DaemonOptions : public qpid::Options {
+ bool daemon;
+ bool quit;
+ bool check;
+ int wait;
+
+ DaemonOptions() : qpid::Options("Daemon options"), daemon(false), quit(false), check(false), wait(10)
+ {
+ addOptions()
+ ("daemon,d", optValue(daemon), "Run as a daemon.")
+ ("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 QpiddOptions : public qpid::Options {
+ CommonOptions common;
+ ModuleOptions module;
+ Broker::Options broker;
+ DaemonOptions daemon;
+ qpid::log::Options log;
+
+ QpiddOptions() : qpid::Options("Options"), common("", "/etc/qpidd.conf") {
+ add(common);
+ add(module);
+ add(broker);
+ add(daemon);
+ add(log);
+ const Plugin::Plugins& plugins=
+ Plugin::getPlugins();
+ for (Plugin::Plugins::const_iterator i = plugins.begin();
+ i != plugins.end();
+ ++i)
+ if ((*i)->getOptions() != 0)
+ add(*(*i)->getOptions());
+ }
+
+ void usage() const {
+ cout << "Usage: qpidd [OPTIONS]" << endl << endl << *this << endl;
+ };
+};
+
+// 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 {
+ CommonOptions common;
+ ModuleOptions module;
+ qpid::log::Options log;
+
+ BootstrapOptions() : qpid::Options("Options"), common("", "/etc/qpidd.conf") {
+ add(common);
+ add(module);
+ add(log);
+ }
+};
+
+// Globals
+shared_ptr<Broker> brokerPtr;
+auto_ptr<QpiddOptions> options;
+
+void shutdownHandler(int /*signal*/){
+ // Note: do not call any async-signal unsafe functions here.
+ // Do any extra shutdown actions in main() after broker->run()
+ brokerPtr->shutdown();
+}
+
+struct QpiddDaemon : public Daemon {
+ /** Code for parent process */
+ void parent() {
+ uint16_t port = wait(options->daemon.wait);
+ if (options->broker.port == 0)
+ cout << port << endl;
+ }
+
+ /** Code for forked child process */
+ void child() {
+ brokerPtr.reset(new Broker(options->broker));
+ uint16_t port=brokerPtr->getPort();
+ ready(port); // Notify parent.
+ brokerPtr->run();
+ brokerPtr.reset();
+ }
+};
+
+void tryShlib(const char* libname, bool noThrow) {
+ try {
+ Shlib shlib(libname);
+ QPID_LOG (info, "Loaded Module: " << libname);
+ }
+ catch (const exception& e) {
+ if (!noThrow)
+ throw;
+ }
+}
+
+void loadModuleDir (string dirname, bool isDefault)
+{
+ fs::path dirPath (dirname, fs::native);
+
+ if (!fs::exists (dirPath))
+ {
+ if (isDefault)
+ return;
+ throw Exception ("Directory not found: " + dirname);
+ }
+
+ 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);
+ }
+}
+
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ {
+ BootstrapOptions bootOptions;
+ 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, argv[0]);
+
+ for (vector<string>::iterator iter = bootOptions.module.load.begin();
+ iter != bootOptions.module.load.end();
+ iter++)
+ tryShlib (iter->data(), false);
+
+ if (!bootOptions.module.noLoad) {
+ bool isDefault = defaultPath == bootOptions.module.loadDir;
+ loadModuleDir (bootOptions.module.loadDir, isDefault);
+ }
+ }
+
+ // Parse options
+ options.reset(new QpiddOptions());
+ 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 (" << PACKAGE_NAME << ") version "
+ << PACKAGE_VERSION << endl;
+ else if (options->common.help)
+ options->usage();
+ return 0;
+ }
+
+ // Options that affect a running daemon.
+ if (options->daemon.check || options->daemon.quit) {
+ pid_t pid = Daemon::getPid(options->broker.port);
+ if (pid < 0)
+ return 1;
+ if (options->daemon.check)
+ cout << pid << endl;
+ if (options->daemon.quit && kill(pid, SIGINT) < 0)
+ throw Exception("Failed to stop daemon: " + strError(errno));
+ return 0;
+ }
+
+ // Starting the broker.
+
+ // Signal handling
+ signal(SIGINT,shutdownHandler);
+ signal(SIGTERM,shutdownHandler);
+ signal(SIGHUP,SIG_IGN); // TODO aconway 2007-07-18: reload config.
+
+ signal(SIGCHLD,SIG_IGN);
+ signal(SIGTSTP,SIG_IGN);
+ signal(SIGTTOU,SIG_IGN);
+ signal(SIGTTIN,SIG_IGN);
+
+ if (options->daemon.daemon) {
+ // Fork the daemon
+ QpiddDaemon d;
+ d.fork();
+ }
+ else { // Non-daemon broker.
+ brokerPtr.reset(new Broker(options->broker));
+ if (options->broker.port == 0)
+ cout << uint16_t(brokerPtr->getPort()) << endl;
+ brokerPtr->run();
+ QPID_LOG(notice, "Shutting down.");
+ }
+ return 0;
+ }
+ catch(const exception& e) {
+ cerr << e.what() << endl;
+ }
+ return 1;
+}
diff --git a/qpid/cpp/src/tests/.valgrind.supp b/qpid/cpp/src/tests/.valgrind.supp
new file mode 100644
index 0000000000..e0abf0dd43
--- /dev/null
+++ b/qpid/cpp/src/tests/.valgrind.supp
@@ -0,0 +1,32 @@
+{
+ 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
+}
+
+{
+ Bogus epoll_ctl error on i386
+ Memcheck:Param
+ epoll_ctl(event)
+ fun:epoll_ctl
+}
+
diff --git a/qpid/cpp/src/tests/.valgrindrc b/qpid/cpp/src/tests/.valgrindrc
new file mode 100644
index 0000000000..4aba7661de
--- /dev/null
+++ b/qpid/cpp/src/tests/.valgrindrc
@@ -0,0 +1,7 @@
+--gen-suppressions=all
+--leak-check=full
+--demangle=yes
+--suppressions=.valgrind.supp
+--num-callers=25
+--trace-children=yes
+
diff --git a/qpid/cpp/src/tests/AccumulatedAckTest.cpp b/qpid/cpp/src/tests/AccumulatedAckTest.cpp
new file mode 100644
index 0000000000..cbe44e6814
--- /dev/null
+++ b/qpid/cpp/src/tests/AccumulatedAckTest.cpp
@@ -0,0 +1,250 @@
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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 "qpid_test_plugin.h"
+#include <iostream>
+#include <list>
+
+using std::list;
+using namespace qpid::framing;
+
+class AccumulatedAckTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(AccumulatedAckTest);
+ CPPUNIT_TEST(testGeneral);
+ CPPUNIT_TEST(testCovers);
+ CPPUNIT_TEST(testUpdateFromCompletionData);
+ CPPUNIT_TEST(testCase1);
+ CPPUNIT_TEST(testCase2);
+ CPPUNIT_TEST(testCase3);
+ CPPUNIT_TEST(testCase4);
+ CPPUNIT_TEST(testConsolidation1);
+ CPPUNIT_TEST(testConsolidation2);
+ CPPUNIT_TEST(testConsolidation3);
+ CPPUNIT_TEST(testConsolidation4);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ 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));
+ }
+
+ void 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++) CPPUNIT_ASSERT(covers(ack, i));
+ CPPUNIT_ASSERT(covers(ack, 9));
+
+ CPPUNIT_ASSERT(!covers(ack, 8));
+ CPPUNIT_ASSERT(!covers(ack, 10));
+
+ ack.consolidate();
+
+ for(int i = 1; i <= 7; i++) CPPUNIT_ASSERT(covers(ack, i));
+ CPPUNIT_ASSERT(covers(ack, 9));
+
+ CPPUNIT_ASSERT(!covers(ack, 8));
+ CPPUNIT_ASSERT(!covers(ack, 10));
+ }
+
+ void testCovers()
+ {
+ AccumulatedAck ack(5);
+ update(ack, 7, 7);
+ update(ack, 9, 9);
+
+ CPPUNIT_ASSERT(covers(ack, 1));
+ CPPUNIT_ASSERT(covers(ack, 2));
+ CPPUNIT_ASSERT(covers(ack, 3));
+ CPPUNIT_ASSERT(covers(ack, 4));
+ CPPUNIT_ASSERT(covers(ack, 5));
+ CPPUNIT_ASSERT(covers(ack, 7));
+ CPPUNIT_ASSERT(covers(ack, 9));
+
+ CPPUNIT_ASSERT(!covers(ack, 6));
+ CPPUNIT_ASSERT(!covers(ack, 8));
+ CPPUNIT_ASSERT(!covers(ack, 10));
+ }
+
+ void 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++) {
+ CPPUNIT_ASSERT(covers(ack, i));
+ }
+ CPPUNIT_ASSERT(!covers(ack, 16));
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 15, ack.mark.getValue());
+ }
+
+ void testCase1()
+ {
+ AccumulatedAck ack(3);
+ update(ack, 1,2);
+ for(int i = 1; i <= 3; i++) CPPUNIT_ASSERT(covers(ack, i));
+ CPPUNIT_ASSERT(!covers(ack, 4));
+ }
+
+ void testCase2()
+ {
+ AccumulatedAck ack(3);
+ update(ack, 3,6);
+ for(int i = 1; i <= 6; i++) CPPUNIT_ASSERT(covers(ack, i));
+ CPPUNIT_ASSERT(!covers(ack, 7));
+ }
+
+ void testCase3()
+ {
+ AccumulatedAck ack(3);
+ update(ack, 4,6);
+ for(int i = 1; i <= 6; i++) {
+ CPPUNIT_ASSERT(covers(ack, i));
+ }
+ CPPUNIT_ASSERT(!covers(ack, 7));
+ }
+
+ void testCase4()
+ {
+ AccumulatedAck ack(3);
+ update(ack, 5,6);
+ for(int i = 1; i <= 6; i++) {
+ if (i == 4) CPPUNIT_ASSERT(!covers(ack, i));
+ else CPPUNIT_ASSERT(covers(ack, i));
+ }
+ CPPUNIT_ASSERT(!covers(ack, 7));
+ }
+
+ void testConsolidation1()
+ {
+ AccumulatedAck ack(3);
+ update(ack, 7,7);
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 3, ack.mark.getValue());
+ CPPUNIT_ASSERT_EQUAL((size_t) 1, ack.ranges.size());
+
+ update(ack, 8,9);
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 3, ack.mark.getValue());
+ CPPUNIT_ASSERT_EQUAL((size_t) 1, ack.ranges.size());
+
+ update(ack, 1,2);
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 3, ack.mark.getValue());
+ CPPUNIT_ASSERT_EQUAL((size_t) 1, ack.ranges.size());
+
+ update(ack, 4,5);
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 5, ack.mark.getValue());
+ CPPUNIT_ASSERT_EQUAL((size_t) 1, ack.ranges.size());
+
+ update(ack, 6,6);
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 9, ack.mark.getValue());
+ CPPUNIT_ASSERT_EQUAL((size_t) 0, ack.ranges.size());
+
+ for(int i = 1; i <= 9; i++) CPPUNIT_ASSERT(covers(ack, i));
+ CPPUNIT_ASSERT(!covers(ack, 10));
+ }
+
+ void testConsolidation2()
+ {
+ AccumulatedAck ack(0);
+ update(ack, 10,12);
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 0, ack.mark.getValue());
+ CPPUNIT_ASSERT_EQUAL((size_t) 1, ack.ranges.size());
+
+ update(ack, 7,9);
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 0, ack.mark.getValue());
+ CPPUNIT_ASSERT_EQUAL((size_t) 1, ack.ranges.size());
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 7, ack.ranges.front().start.getValue());
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 12, ack.ranges.front().end.getValue());
+
+ update(ack, 5,7);
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 0, ack.mark.getValue());
+ CPPUNIT_ASSERT_EQUAL((size_t) 1, ack.ranges.size());
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 5, ack.ranges.front().start.getValue());
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 12, ack.ranges.front().end.getValue());
+
+ update(ack, 3,4);
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 0, ack.mark.getValue());
+ CPPUNIT_ASSERT_EQUAL((size_t) 1, ack.ranges.size());
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 3, ack.ranges.front().start.getValue());
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 12, ack.ranges.front().end.getValue());
+
+ update(ack, 1,2);
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 12, ack.mark.getValue());
+ CPPUNIT_ASSERT_EQUAL((size_t) 0, ack.ranges.size());
+
+ for(int i = 1; i <= 12; i++) CPPUNIT_ASSERT(covers(ack, i));
+ CPPUNIT_ASSERT(!covers(ack, 13));
+ }
+
+ void testConsolidation3()
+ {
+ AccumulatedAck ack(0);
+ update(ack, 10,12);
+ update(ack, 6,7);
+ update(ack, 3,4);
+ update(ack, 1,15);
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 15, ack.mark.getValue());
+ CPPUNIT_ASSERT_EQUAL((size_t) 0, ack.ranges.size());
+ }
+
+ void 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++) {
+ CPPUNIT_ASSERT(covers(ack, i));
+ }
+ CPPUNIT_ASSERT(!covers(ack, 16));
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 15, ack.mark.getValue());
+ }
+
+};
+
+// Make this test suite a plugin.
+CPPUNIT_PLUGIN_IMPLEMENT();
+CPPUNIT_TEST_SUITE_REGISTRATION(AccumulatedAckTest);
+
diff --git a/qpid/cpp/src/tests/Array.cpp b/qpid/cpp/src/tests/Array.cpp
new file mode 100644
index 0000000000..336e57b485
--- /dev/null
+++ b/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());
+ }
+}
+
+BOOST_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);
+}
+
+BOOST_AUTO_TEST_CASE(testAssignment)
+{
+ 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/qpid/cpp/src/tests/BasicP2PTest.cpp b/qpid/cpp/src/tests/BasicP2PTest.cpp
new file mode 100644
index 0000000000..b202f88ca6
--- /dev/null
+++ b/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(TestOptions& 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, TestOptions& 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/qpid/cpp/src/tests/BasicP2PTest.h b/qpid/cpp/src/tests/BasicP2PTest.h
new file mode 100644
index 0000000000..3f0a3704f5
--- /dev/null
+++ b/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, TestOptions& options);
+};
+
+}
+
+#endif
diff --git a/qpid/cpp/src/tests/BasicPubSubTest.cpp b/qpid/cpp/src/tests/BasicPubSubTest.cpp
new file mode 100644
index 0000000000..623194d331
--- /dev/null
+++ b/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(TestOptions& 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(TestOptions& 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, TestOptions& 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/qpid/cpp/src/tests/BasicPubSubTest.h b/qpid/cpp/src/tests/BasicPubSubTest.h
new file mode 100644
index 0000000000..c3f8020b3a
--- /dev/null
+++ b/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, TestOptions& options);
+};
+
+}
+
+#endif
diff --git a/qpid/cpp/src/tests/Blob.cpp b/qpid/cpp/src/tests/Blob.cpp
new file mode 100644
index 0000000000..d27c0bbd85
--- /dev/null
+++ b/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 ;
+
+BOOST_AUTO_TEST_CASE(testCtor) {
+ {
+ 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);
+}
+
+
+BOOST_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);
+}
+
+
+BOOST_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/qpid/cpp/src/tests/BrokerFixture.h b/qpid/cpp/src/tests/BrokerFixture.h
new file mode 100644
index 0000000000..83b3f621c7
--- /dev/null
+++ b/qpid/cpp/src/tests/BrokerFixture.h
@@ -0,0 +1,108 @@
+#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/sys/Thread.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"
+
+/**
+ * A fixture with an in-process broker.
+ */
+struct BrokerFixture {
+ typedef qpid::broker::Broker Broker;
+ typedef boost::shared_ptr<Broker> BrokerPtr;
+
+ BrokerPtr broker;
+ qpid::sys::Thread brokerThread;
+
+ BrokerFixture() {
+ Broker::Options opts;
+ 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();
+ 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());
+ }
+};
+
+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(); }
+};
+
+/**
+ * A BrokerFixture with open Connection, Session and
+ * SubscriptionManager and LocalQueue for convenience.
+ */
+template <class ConnectionType>
+struct SessionFixtureT : BrokerFixture {
+ ConnectionType connection;
+ qpid::client::Session session;
+ qpid::client::SubscriptionManager subs;
+ qpid::client::LocalQueue lq;
+
+ SessionFixtureT() : connection(broker->getPort()),
+ session(connection.newSession(qpid::client::ASYNC)),
+ subs(session)
+ {}
+
+ ~SessionFixtureT() {
+ connection.close();
+ }
+};
+
+typedef SessionFixtureT<LocalConnection> SessionFixture;
+typedef SessionFixtureT<ProxyConnection> ProxySessionFixture;
+
+
+#endif /*!TESTS_BROKERFIXTURE_H*/
diff --git a/qpid/cpp/src/tests/ClientChannelTest.cpp b/qpid/cpp/src/tests/ClientChannelTest.cpp
new file mode 100644
index 0000000000..605d5e4885
--- /dev/null
+++ b/qpid/cpp/src/tests/ClientChannelTest.cpp
@@ -0,0 +1,220 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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 "qpid_test_plugin.h"
+#include "BrokerFixture.h"
+#include "qpid/client/Channel.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/Queue.h"
+#include "qpid/client/Exchange.h"
+#include "qpid/client/MessageListener.h"
+#include "qpid/client/BasicMessageChannel.h"
+#include "qpid/client/MessageMessageChannel.h"
+
+using namespace std;
+using namespace boost;
+using namespace qpid::client;
+using namespace qpid::sys;
+using namespace qpid::framing;
+
+/// Small frame size so we can create fragmented messages.
+const size_t FRAME_MAX = 256;
+
+
+/**
+ * Test base for client API using an in-process broker.
+ * The test base defines the tests methods, derived classes
+ * instantiate the channel in Basic or Message mode.
+ */
+class ChannelTestBase : public CppUnit::TestCase, public SessionFixture
+{
+ struct Listener: public qpid::client::MessageListener {
+ vector<Message> messages;
+ Monitor monitor;
+ void received(Message& msg) {
+ Mutex::ScopedLock l(monitor);
+ messages.push_back(msg);
+ monitor.notifyAll();
+ }
+ };
+
+ const std::string qname;
+ const std::string data;
+ Queue queue;
+ Exchange exchange;
+ Listener listener;
+
+ protected:
+ boost::scoped_ptr<Channel> channel;
+
+ public:
+
+ ChannelTestBase()
+ : qname("testq"), data("hello"),
+ queue(qname, true), exchange("", Exchange::DIRECT_EXCHANGE)
+ {}
+
+ void setUp() {
+ CPPUNIT_ASSERT(channel);
+ connection.openChannel(*channel);
+ CPPUNIT_ASSERT(channel->getId() != 0);
+ channel->declareQueue(queue);
+ }
+
+ void testPublishGet() {
+ Message pubMsg(data);
+ pubMsg.getHeaders().setString("hello", "world");
+ channel->publish(pubMsg, exchange, qname);
+ Message getMsg;
+ CPPUNIT_ASSERT(channel->get(getMsg, queue));
+ CPPUNIT_ASSERT_EQUAL(data, getMsg.getData());
+ CPPUNIT_ASSERT_EQUAL(string("world"),
+ getMsg.getHeaders().getString("hello"));
+ CPPUNIT_ASSERT(!channel->get(getMsg, queue)); // Empty queue
+ }
+
+ void testGetNoContent() {
+ Message pubMsg;
+ pubMsg.getHeaders().setString("hello", "world");
+ channel->publish(pubMsg, exchange, qname);
+ Message getMsg;
+ CPPUNIT_ASSERT(channel->get(getMsg, queue));
+ CPPUNIT_ASSERT(getMsg.getData().empty());
+ CPPUNIT_ASSERT_EQUAL(string("world"),
+ getMsg.getHeaders().getString("hello"));
+ }
+
+ void testConsumeCancel() {
+ string tag; // Broker assigned
+ channel->consume(queue, tag, &listener);
+ channel->start();
+ CPPUNIT_ASSERT_EQUAL(size_t(0), listener.messages.size());
+ channel->publish(Message("a"), exchange, qname);
+ {
+ Mutex::ScopedLock l(listener.monitor);
+ Time deadline(now() + 1*TIME_SEC);
+ while (listener.messages.size() != 1) {
+ CPPUNIT_ASSERT(listener.monitor.wait(deadline));
+ }
+ }
+ CPPUNIT_ASSERT_EQUAL(size_t(1), listener.messages.size());
+ CPPUNIT_ASSERT_EQUAL(string("a"), listener.messages[0].getData());
+
+ channel->publish(Message("b"), exchange, qname);
+ channel->publish(Message("c"), exchange, qname);
+ {
+ Mutex::ScopedLock l(listener.monitor);
+ while (listener.messages.size() != 3) {
+ CPPUNIT_ASSERT(listener.monitor.wait(1*TIME_SEC));
+ }
+ }
+ CPPUNIT_ASSERT_EQUAL(size_t(3), listener.messages.size());
+ CPPUNIT_ASSERT_EQUAL(string("b"), listener.messages[1].getData());
+ CPPUNIT_ASSERT_EQUAL(string("c"), listener.messages[2].getData());
+
+ channel->cancel(tag);
+ channel->publish(Message("d"), exchange, qname);
+ CPPUNIT_ASSERT_EQUAL(size_t(3), listener.messages.size());
+ {
+ Mutex::ScopedLock l(listener.monitor);
+ CPPUNIT_ASSERT(!listener.monitor.wait(TIME_SEC/2));
+ }
+ Message msg;
+ CPPUNIT_ASSERT(channel->get(msg, queue));
+ CPPUNIT_ASSERT_EQUAL(string("d"), msg.getData());
+ }
+
+ // Consume already-published messages
+ void testConsumePublished() {
+ Message pubMsg("x");
+ pubMsg.getHeaders().setString("y", "z");
+ channel->publish(pubMsg, exchange, qname);
+ string tag;
+ channel->consume(queue, tag, &listener);
+ CPPUNIT_ASSERT_EQUAL(size_t(0), listener.messages.size());
+ channel->start();
+ {
+ Mutex::ScopedLock l(listener.monitor);
+ while (listener.messages.size() != 1)
+ CPPUNIT_ASSERT(listener.monitor.wait(1*TIME_SEC));
+ }
+ CPPUNIT_ASSERT_EQUAL(string("x"), listener.messages[0].getData());
+ CPPUNIT_ASSERT_EQUAL(string("z"),
+ listener.messages[0].getHeaders().getString("y"));
+ }
+
+ void testGetFragmentedMessage() {
+ string longStr(FRAME_MAX*2, 'x'); // Longer than max frame size.
+ channel->publish(Message(longStr), exchange, qname);
+ Message getMsg;
+ CPPUNIT_ASSERT(channel->get(getMsg, queue));
+ }
+
+ void testConsumeFragmentedMessage() {
+ string xx(FRAME_MAX*2, 'x');
+ channel->publish(Message(xx), exchange, qname);
+ channel->start();
+ string tag;
+ channel->consume(queue, tag, &listener);
+ string yy(FRAME_MAX*2, 'y');
+ channel->publish(Message(yy), exchange, qname);
+ {
+ Mutex::ScopedLock l(listener.monitor);
+ while (listener.messages.size() != 2)
+ CPPUNIT_ASSERT(listener.monitor.wait(1*TIME_SEC));
+ }
+ CPPUNIT_ASSERT_EQUAL(xx, listener.messages[0].getData());
+ CPPUNIT_ASSERT_EQUAL(yy, listener.messages[1].getData());
+ }
+};
+
+class BasicChannelTest : public ChannelTestBase {
+ CPPUNIT_TEST_SUITE(BasicChannelTest);
+ CPPUNIT_TEST(testPublishGet);
+ CPPUNIT_TEST(testGetNoContent);
+ CPPUNIT_TEST(testConsumeCancel);
+ CPPUNIT_TEST(testConsumePublished);
+ CPPUNIT_TEST(testGetFragmentedMessage);
+ CPPUNIT_TEST(testConsumeFragmentedMessage);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ BasicChannelTest(){
+ channel.reset(new Channel(false, 500, Channel::AMQP_08));
+ }
+};
+
+class MessageChannelTest : public ChannelTestBase {
+ CPPUNIT_TEST_SUITE(MessageChannelTest);
+ CPPUNIT_TEST(testPublishGet);
+ CPPUNIT_TEST(testGetNoContent);
+ CPPUNIT_TEST(testGetFragmentedMessage);
+ CPPUNIT_TEST_SUITE_END();
+ public:
+ MessageChannelTest() {
+ channel.reset(new Channel(false, 500, Channel::AMQP_09));
+ }
+};
+
+// Make this test suite a plugin.
+CPPUNIT_PLUGIN_IMPLEMENT();
+CPPUNIT_TEST_SUITE_REGISTRATION(BasicChannelTest);
+CPPUNIT_TEST_SUITE_REGISTRATION(MessageChannelTest);
diff --git a/qpid/cpp/src/tests/ClientSessionTest.cpp b/qpid/cpp/src/tests/ClientSessionTest.cpp
new file mode 100644
index 0000000000..7a997db327
--- /dev/null
+++ b/qpid/cpp/src/tests/ClientSessionTest.cpp
@@ -0,0 +1,220 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/Dispatcher.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 <vector>
+
+QPID_AUTO_TEST_SUITE(ClientSessionTest)
+
+using namespace qpid::client;
+using namespace qpid::client::arg;
+using namespace qpid::framing;
+using namespace qpid;
+using qpid::sys::Monitor;
+using std::string;
+using std::cout;
+using std::endl;
+using namespace boost;
+
+
+struct DummyListener : public sys::Runnable, public MessageListener {
+ std::vector<Message> messages;
+ string name;
+ uint expected;
+ Dispatcher dispatcher;
+
+ DummyListener(Session& session, const string& n, uint ex) :
+ name(n), expected(ex), dispatcher(session) {}
+
+ void run()
+ {
+ dispatcher.listen(name, this);
+ dispatcher.run();
+ }
+
+ void received(Message& msg)
+ {
+ messages.push_back(msg);
+ if (--expected == 0)
+ dispatcher.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
+{
+ void declareSubscribe(const string& q="my-queue",
+ const string& dest="my-dest")
+ {
+ 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
+ }
+};
+
+BOOST_FIXTURE_TEST_CASE(testQueueQuery, ClientSessionFixture) {
+ session =connection.newSession(ASYNC);
+ session.queueDeclare(queue="my-queue", alternateExchange="amq.fanout", exclusive=true, autoDelete=true);
+ TypedResult<QueueQueryResult> result = session.queueQuery(string("my-queue"));
+ BOOST_CHECK_EQUAL(false, result.get().getDurable());
+ BOOST_CHECK_EQUAL(true, result.get().getExclusive());
+ BOOST_CHECK_EQUAL(string("amq.fanout"),
+ result.get().getAlternateExchange());
+}
+
+BOOST_FIXTURE_TEST_CASE(testTransfer, ClientSessionFixture)
+{
+ session=connection.newSession(ASYNC);
+ declareSubscribe();
+ session.messageTransfer(content=TransferContent("my-message", "my-queue"));
+ //get & test the message:
+ FrameSet::shared_ptr msg = session.get();
+ BOOST_CHECK(msg->isA<MessageTransferBody>());
+ BOOST_CHECK_EQUAL(string("my-message"), msg->getContent());
+ //confirm receipt:
+ session.getExecution().completed(msg->getId(), true, true);
+}
+
+BOOST_FIXTURE_TEST_CASE(testDispatcher, ClientSessionFixture)
+{
+ session =connection.newSession(ASYNC);
+ declareSubscribe();
+ size_t count = 100;
+ for (size_t i = 0; i < count; ++i)
+ session.messageTransfer(content=TransferContent(lexical_cast<string>(i), "my-queue"));
+ DummyListener listener(session, "my-dest", count);
+ listener.run();
+ BOOST_REQUIRE_EQUAL(count, listener.messages.size());
+ for (size_t i = 0; i < count; ++i)
+ BOOST_CHECK_EQUAL(lexical_cast<string>(i), listener.messages[i].getData());
+}
+
+/* FIXME aconway 2008-01-28: hangs
+BOOST_FIXTURE_TEST_CASE(testDispatcherThread, ClientSessionFixture)
+{
+ session =connection.newSession(ASYNC);
+ declareSubscribe();
+ size_t count = 10000;
+ DummyListener listener(session, "my-dest", count);
+ sys::Thread t(listener);
+ for (size_t i = 0; i < count; ++i) {
+ session.messageTransfer(content=TransferContent(lexical_cast<string>(i), "my-queue"));
+ if (i%100 == 0) cout << "T" << i << std::flush;
+ }
+ t.join();
+ BOOST_REQUIRE_EQUAL(count, listener.messages.size());
+ for (size_t i = 0; i < count; ++i)
+ BOOST_CHECK_EQUAL(lexical_cast<string>(i), listener.messages[i].getData());
+}
+*/
+
+BOOST_FIXTURE_TEST_CASE(_FIXTURE, ClientSessionFixture)
+{
+ session =connection.newSession(ASYNC, 0);
+ session.suspend(); // session has 0 timeout.
+ try {
+ connection.resume(session);
+ BOOST_FAIL("Expected InvalidArgumentException.");
+ } catch(const InternalErrorException&) {}
+}
+
+BOOST_FIXTURE_TEST_CASE(testUseSuspendedError, ClientSessionFixture)
+{
+ session =connection.newSession(ASYNC, 60);
+ session.suspend();
+ try {
+ session.exchangeQuery(name="amq.fanout");
+ BOOST_FAIL("Expected session suspended exception");
+ } catch(const CommandInvalidException&) {}
+}
+
+BOOST_FIXTURE_TEST_CASE(testSuspendResume, ClientSessionFixture)
+{
+ session =connection.newSession(ASYNC, 60);
+ declareSubscribe();
+ session.suspend();
+ // Make sure we are still subscribed after resume.
+ connection.resume(session);
+ session.messageTransfer(content=TransferContent("my-message", "my-queue"));
+ FrameSet::shared_ptr msg = session.get();
+ BOOST_CHECK_EQUAL(string("my-message"), msg->getContent());
+}
+
+/**
+ * Currently broken due to a deadlock in SessionCore
+ *
+BOOST_FIXTURE_TEST_CASE(testSendToSelf, SessionFixture) {
+ // Deadlock if SubscriptionManager run() concurrent with session ack.
+ SimpleListener mylistener;
+ session.queueDeclare(queue="myq", exclusive=true, autoDelete=true);
+ subs.subscribe(mylistener, "myq", "myq");
+ sys::Thread runner(subs);//start dispatcher thread
+ string data("msg");
+ Message msg(data, "myq");
+ const uint count=10000;
+ for (uint i = 0; i < count; ++i) {
+ session.messageTransfer(content=msg);
+ }
+ mylistener.waitFor(count);
+ subs.cancel("myq");
+ subs.stop();
+ 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_SUITE_END()
+
diff --git a/qpid/cpp/src/tests/ConcurrentQueue.cpp b/qpid/cpp/src/tests/ConcurrentQueue.cpp
new file mode 100644
index 0000000000..c6ca40e897
--- /dev/null
+++ b/qpid/cpp/src/tests/ConcurrentQueue.cpp
@@ -0,0 +1,208 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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
+ * Compare alternative implementations for BlockingQueue.
+ */
+
+#include "qpid/sys/BlockingQueue.h"
+#include "qpid/sys/Thread.h"
+#include "qpid/sys/Monitor.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/sys/Time.h"
+
+#include <boost/test/test_tools.hpp>
+#include <boost/bind.hpp>
+
+#include <deque>
+#include <vector>
+#include <iostream>
+
+#include "time.h"
+
+using namespace qpid::sys;
+using namespace std;
+
+template <class T> class DualVectorDualLockQueue {
+ public:
+ /** Optionally specify initial capacity of the queue to minimize
+ * re-allocation.
+ */
+ DualVectorDualLockQueue(size_t capacity=16) {
+ pushVec.reserve(capacity);
+ popVec.reserve(capacity);
+ popIter = popVec.end();
+ }
+
+ /** Push a data item onto the back of the queue */
+ void push(const T& data) {
+ Mutex::ScopedLock l(pushLock);
+ pushVec.push_back(data);
+ }
+
+ /** If the queue is non-empty, pop the front item into data and
+ * return true. If the queue is empty, return false
+ */
+ bool tryPop(T& data) {
+ Mutex::ScopedLock l(popLock);
+ if (popIter == popVec.end()) {
+ popVec.clear();
+ Mutex::ScopedLock l(pushLock);
+ pushVec.swap(popVec);
+ popIter = popVec.begin();
+ }
+ if (popIter == popVec.end())
+ return false;
+ else {
+ data = *popIter++;
+ return true;
+ }
+ }
+
+ private:
+ Mutex pushLock, popLock;
+ std::vector<T> pushVec, popVec;
+ typename std::vector<T>::iterator popIter;
+};
+
+template <class T> struct LockedDequeQueue : public BlockingQueue<T> {
+ /** size_t ignored, can't pre-allocate space in a dequeue */
+ LockedDequeQueue(size_t=0) {};
+};
+
+// ================ Test code.
+
+/** Pause by sleeping */
+void nsleep(const Duration& delay) {
+ static Monitor m;
+ AbsTime stop(now(), delay);
+ while (now() < stop)
+ m.wait(stop);
+}
+
+/** Pause by spinning */
+void nspin(const Duration& delay) {
+ AbsTime stop(now(), delay);
+ while (now() < stop)
+ ;
+}
+
+/** Unlocked fake queue for comparison */
+struct NullQueue {
+ NullQueue(int items=0) : npush(items), npop(items) {}
+ void push(int) { --npush; }
+ bool tryPop(int& n) {
+ if (npop == 0)
+ return false;
+ else {
+ n=npop--;
+ return true;
+ }
+ }
+ volatile int npush, npop;
+};
+
+
+// Global test parameters.
+int items;
+Duration delay(0);
+boost::function<void()> npause;
+
+template <class Q>
+struct Pusher : public Runnable {
+ Pusher(Q& q) : queue(q) {}
+ void run() {
+ for (int i=items; i > 0; i--) {
+ queue.push(i);
+ npause();
+ }
+ }
+ Q& queue;
+};
+
+template <class Q>
+struct Popper : public Runnable {
+ Popper(Q& q) : queue(q) {}
+ void run() {
+ for (int i=items; i > 0; i--) {
+ int n;
+ if (queue.tryPop(n))
+ BOOST_REQUIRE_EQUAL(i,n);
+ npause();
+ }
+ }
+ Q& queue;
+};
+
+ostream& operator<<(ostream& out, const Duration& d) {
+ return out << double(d)/TIME_MSEC << " msecs";
+}
+
+void report(const char* s, const Duration &d) {
+ cout << s << ": " << d
+ << " (" << (double(items)*TIME_SEC)/d << " push-pops/sec" << ")"
+ << endl;
+}
+
+template <class Q, class PusherT=Pusher<Q>, class PopperT=Popper<Q> >
+struct Timer {
+ static Duration time() {
+ cout << endl << "==" << typeid(Q).name() << endl;
+
+ Q queue(items);
+ PusherT pusher(queue);
+ PopperT popper(queue);
+
+ // Serial
+ AbsTime start=now();
+ pusher.run();
+ popper.run();
+ Duration serial(start,now());
+ report ("Serial", serial);
+
+ // Concurrent
+ start=now();
+ Thread pushThread(pusher);
+ Thread popThread(popper);
+ pushThread.join();
+ popThread.join();
+ Duration concurrent(start,now());
+ report ("Concurrent", concurrent);
+
+ cout << "Serial/concurrent: " << double(serial)/concurrent << endl;
+ return concurrent;
+ }
+};
+
+int test_main(int argc, char** argv) {
+ items = (argc > 1) ? atoi(argv[1]) : 250*1000;
+ delay = (argc > 2) ? atoi(argv[2]) : 4*1000;
+ npause=boost::bind(nspin, delay);
+
+ cout << "Push/pop " << items << " items, delay=" << delay << endl;
+ Timer<NullQueue>::time();
+ Duration dv = Timer<DualVectorDualLockQueue<int> >::time();
+ Duration d = Timer<LockedDequeQueue<int> >::time();
+ cout << endl;
+ cout << "Ratio deque/dual vector=" << double(d)/dv << endl;
+ return 0;
+}
+// namespace
diff --git a/qpid/cpp/src/tests/Cpg.cpp b/qpid/cpp/src/tests/Cpg.cpp
new file mode 100644
index 0000000000..e8339bf773
--- /dev/null
+++ b/qpid/cpp/src/tests/Cpg.cpp
@@ -0,0 +1,115 @@
+/*
+ *
+ * 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/cluster/Cpg.h"
+#include "qpid/framing/AMQBody.h"
+
+#include <boost/bind.hpp>
+#include "unit_test.h"
+
+#include <string>
+#include <iostream>
+#include <iterator>
+#include <vector>
+#include <algorithm>
+
+QPID_AUTO_TEST_SUITE(CpgTestSuite)
+
+
+using namespace std;
+using namespace qpid::cluster;
+using namespace qpid::framing;
+
+// For debugging: op << for CPG types.
+
+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;
+}
+
+struct Callback : public Cpg::Handler {
+ Callback(const string group_) : group(group_) {}
+ string group;
+ vector<string> delivered;
+ vector<int> configChanges;
+
+ void deliver (
+ cpg_handle_t /*handle*/,
+ struct cpg_name *grp,
+ uint32_t /*nodeid*/,
+ uint32_t /*pid*/,
+ void* msg,
+ int msg_len)
+ {
+ BOOST_CHECK_EQUAL(group, Cpg::str(*grp));
+ delivered.push_back(string((char*)msg,msg_len));
+ }
+
+ void configChange(
+ cpg_handle_t /*handle*/,
+ struct cpg_name *grp,
+ struct cpg_address */*members*/, int nMembers,
+ struct cpg_address */*left*/, int nLeft,
+ struct cpg_address */*joined*/, int nJoined
+ )
+ {
+ BOOST_CHECK_EQUAL(group, Cpg::str(*grp));
+ configChanges.push_back(nMembers);
+ BOOST_MESSAGE("configChange: "<<
+ nLeft<<" left "<<
+ nJoined<<" joined "<<
+ nMembers<<" members.");
+ }
+};
+
+BOOST_AUTO_TEST_CASE(CpgBasic) {
+ // Verify basic functionality of cpg. This will catch any
+ // openais configuration or permission errors.
+ //
+ Cpg::Name group("CpgBasic");
+ Callback cb(group.str());
+ Cpg cpg(cb);
+ cpg.join(group);
+ iovec iov = { (void*)"Hello!", 6 };
+ cpg.mcast(group, &iov, 1);
+ cpg.leave(group);
+ cpg.dispatchSome();
+
+ BOOST_REQUIRE_EQUAL(1u, cb.delivered.size());
+ BOOST_CHECK_EQUAL("Hello!", cb.delivered.front());
+ BOOST_REQUIRE_EQUAL(2u, cb.configChanges.size());
+ BOOST_CHECK_EQUAL(1, cb.configChanges[0]);
+ BOOST_CHECK_EQUAL(0, cb.configChanges[1]);
+}
+
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/DeliveryRecordTest.cpp b/qpid/cpp/src/tests/DeliveryRecordTest.cpp
new file mode 100644
index 0000000000..9487f743d6
--- /dev/null
+++ b/qpid/cpp/src/tests/DeliveryRecordTest.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 "qpid/broker/DeliveryRecord.h"
+#include "qpid_test_plugin.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;
+
+class DeliveryRecordTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(DeliveryRecordTest);
+ CPPUNIT_TEST(testSort);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+
+ void 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++) {
+ records.push_back(DeliveryRecord(QueuedMessage(0), Queue::shared_ptr(), "tag", DeliveryToken::shared_ptr(), *i, false, false));
+ }
+ records.sort();
+
+ SequenceNumber expected(0);
+ for (list<DeliveryRecord>::iterator i = records.begin(); i != records.end(); i++) {
+ CPPUNIT_ASSERT(i->matches(++expected));
+ }
+ }
+};
+
+// Make this test suite a plugin.
+CPPUNIT_PLUGIN_IMPLEMENT();
+CPPUNIT_TEST_SUITE_REGISTRATION(DeliveryRecordTest);
+
diff --git a/qpid/cpp/src/tests/DispatcherTest.cpp b/qpid/cpp/src/tests/DispatcherTest.cpp
new file mode 100644
index 0000000000..7631956acc
--- /dev/null
+++ b/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/qpid/cpp/src/tests/DtxWorkRecordTest.cpp b/qpid/cpp/src/tests/DtxWorkRecordTest.cpp
new file mode 100644
index 0000000000..d7d151f8d6
--- /dev/null
+++ b/qpid/cpp/src/tests/DtxWorkRecordTest.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.
+ *
+ */
+#include "qpid/broker/DtxWorkRecord.h"
+#include "qpid_test_plugin.h"
+#include <iostream>
+#include <vector>
+#include "TxMocks.h"
+
+using namespace qpid::broker;
+using boost::static_pointer_cast;
+
+class DtxWorkRecordTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(DtxWorkRecordTest);
+ CPPUNIT_TEST(testOnePhaseCommit);
+ CPPUNIT_TEST(testFailOnOnePhaseCommit);
+ CPPUNIT_TEST(testTwoPhaseCommit);
+ CPPUNIT_TEST(testFailOnTwoPhaseCommit);
+ CPPUNIT_TEST(testRollback);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+
+ void 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();
+ CPPUNIT_ASSERT(store.isCommitted());
+ opA->check();
+ opB->check();
+ }
+
+ void 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);
+
+ CPPUNIT_ASSERT(store.isAborted());
+ store.check();
+
+ opA->check();
+ opB->check();
+ opC->check();
+ }
+
+ void 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);
+
+ CPPUNIT_ASSERT(work.prepare());
+ CPPUNIT_ASSERT(store.isPrepared());
+ work.commit(false);
+ store.check();
+ CPPUNIT_ASSERT(store.isCommitted());
+ opA->check();
+ opB->check();
+ }
+
+ void 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);
+
+ CPPUNIT_ASSERT(!work.prepare());
+ CPPUNIT_ASSERT(store.isAborted());
+ store.check();
+ opA->check();
+ opB->check();
+ opC->check();
+ }
+
+ void 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);
+
+ CPPUNIT_ASSERT(work.prepare());
+ CPPUNIT_ASSERT(store.isPrepared());
+ work.rollback();
+ store.check();
+ CPPUNIT_ASSERT(store.isAborted());
+ opA->check();
+ opB->check();
+ }
+};
+
+// Make this test suite a plugin.
+CPPUNIT_PLUGIN_IMPLEMENT();
+CPPUNIT_TEST_SUITE_REGISTRATION(DtxWorkRecordTest);
+
diff --git a/qpid/cpp/src/tests/EventChannelTest.cpp b/qpid/cpp/src/tests/EventChannelTest.cpp
new file mode 100644
index 0000000000..6d8d64e165
--- /dev/null
+++ b/qpid/cpp/src/tests/EventChannelTest.cpp
@@ -0,0 +1,187 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/posix/EventChannel.h"
+#include "qpid/sys/posix/check.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/sys/Socket.h"
+#include "qpid/sys/Thread.h"
+#include "qpid_test_plugin.h"
+
+#include <sys/socket.h>
+#include <signal.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <iostream>
+
+using namespace qpid::sys;
+
+
+const char hello[] = "hello";
+const size_t size = sizeof(hello);
+
+struct RunMe : public Runnable
+{
+ bool ran;
+ RunMe() : ran(false) {}
+ void run() { ran = true; }
+};
+
+class EventChannelTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(EventChannelTest);
+ CPPUNIT_TEST(testEvent);
+ CPPUNIT_TEST(testRead);
+ CPPUNIT_TEST(testFailedRead);
+ CPPUNIT_TEST(testWrite);
+ CPPUNIT_TEST(testFailedWrite);
+ CPPUNIT_TEST(testReadWrite);
+ CPPUNIT_TEST(testAccept);
+ CPPUNIT_TEST_SUITE_END();
+
+ private:
+ EventChannel::shared_ptr ec;
+ int pipe[2];
+ char readBuf[size];
+
+ public:
+
+ void setUp()
+ {
+ memset(readBuf, size, 0);
+ ec = EventChannel::create();
+ if (::pipe(pipe) != 0) throw QPID_POSIX_ERROR(errno);
+ // Ignore SIGPIPE, otherwise we will crash writing to broken pipe.
+ signal(SIGPIPE, SIG_IGN);
+ }
+
+ // Verify that calling getEvent returns event.
+ template <class T> bool isNextEvent(T& event)
+ {
+ return &event == dynamic_cast<T*>(ec->getEvent());
+ }
+
+ template <class T> bool isNextEventOk(T& event)
+ {
+ Event* next = ec->getEvent();
+ if (next) next->throwIfError();
+ return &event == next;
+ }
+
+ void testEvent()
+ {
+ RunMe runMe;
+ CPPUNIT_ASSERT(!runMe.ran);
+ // Instances of Event just pass thru the channel immediately.
+ Event e(runMe.functor());
+ ec->postEvent(e);
+ CPPUNIT_ASSERT(isNextEventOk(e));
+ e.dispatch();
+ CPPUNIT_ASSERT(runMe.ran);
+ }
+
+ void testRead() {
+ ReadEvent re(pipe[0], readBuf, size);
+ ec->postEvent(re);
+ CPPUNIT_ASSERT_EQUAL(ssize_t(size), ::write(pipe[1], hello, size));
+ CPPUNIT_ASSERT(isNextEventOk(re));
+ CPPUNIT_ASSERT_EQUAL(size, re.getSize());
+ CPPUNIT_ASSERT_EQUAL(std::string(hello), std::string(readBuf));
+ }
+
+ void testFailedRead()
+ {
+ ReadEvent re(pipe[0], readBuf, size);
+ ec->postEvent(re);
+
+ // EOF before all data read.
+ ::close(pipe[1]);
+ CPPUNIT_ASSERT(isNextEvent(re));
+ CPPUNIT_ASSERT(re.hasError());
+ try {
+ re.throwIfError();
+ CPPUNIT_FAIL("Expected Exception.");
+ }
+ catch (const qpid::Exception&) { }
+
+ // Bad file descriptor. Note in this case we fail
+ // in postEvent and throw immediately.
+ try {
+ ReadEvent bad;
+ ec->postEvent(bad);
+ CPPUNIT_FAIL("Expected Exception.");
+ }
+ catch (const qpid::Exception&) { }
+ }
+
+ void testWrite() {
+ WriteEvent wr(pipe[1], hello, size);
+ ec->postEvent(wr);
+ CPPUNIT_ASSERT(isNextEventOk(wr));
+ CPPUNIT_ASSERT_EQUAL(ssize_t(size), ::read(pipe[0], readBuf, size));;
+ CPPUNIT_ASSERT_EQUAL(std::string(hello), std::string(readBuf));
+ }
+
+ void testFailedWrite() {
+ WriteEvent wr(pipe[1], hello, size);
+ ::close(pipe[0]);
+ ec->postEvent(wr);
+ CPPUNIT_ASSERT(isNextEvent(wr));
+ CPPUNIT_ASSERT(wr.hasError());
+ }
+
+ void testReadWrite()
+ {
+ ReadEvent re(pipe[0], readBuf, size);
+ WriteEvent wr(pipe[1], hello, size);
+ ec->postEvent(re);
+ ec->postEvent(wr);
+ ec->getEvent();
+ ec->getEvent();
+ CPPUNIT_ASSERT_EQUAL(std::string(hello), std::string(readBuf));
+ }
+
+ void testAccept() {
+ Socket s = Socket::createTcp();
+ int port = s.listen(0, 10);
+ CPPUNIT_ASSERT(port != 0);
+
+ AcceptEvent ae(s.fd());
+ ec->postEvent(ae);
+ Socket client = Socket::createTcp();
+ client.connect("localhost", port);
+ CPPUNIT_ASSERT(isNextEvent(ae));
+ ae.dispatch();
+
+ // Verify client writes are read by the accepted descriptor.
+ char readBuf[size];
+ ReadEvent re(ae.getAcceptedDesscriptor(), readBuf, size);
+ ec->postEvent(re);
+ CPPUNIT_ASSERT_EQUAL(ssize_t(size), client.send(hello, sizeof(hello)));
+ CPPUNIT_ASSERT(isNextEvent(re));
+ re.dispatch();
+ CPPUNIT_ASSERT_EQUAL(std::string(hello), std::string(readBuf));
+ }
+};
+
+// Make this test suite a plugin.
+CPPUNIT_PLUGIN_IMPLEMENT();
+CPPUNIT_TEST_SUITE_REGISTRATION(EventChannelTest);
+
diff --git a/qpid/cpp/src/tests/EventChannelThreadsTest.cpp b/qpid/cpp/src/tests/EventChannelThreadsTest.cpp
new file mode 100644
index 0000000000..22ea57d675
--- /dev/null
+++ b/qpid/cpp/src/tests/EventChannelThreadsTest.cpp
@@ -0,0 +1,247 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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 "qpid/sys/Socket.h"
+#include "qpid/sys/posix/EventChannelThreads.h"
+#include "qpid_test_plugin.h"
+
+
+using namespace std;
+
+using namespace qpid::sys;
+
+const int nConnections = 5;
+const int nMessages = 10; // Messages read/written per connection.
+
+
+// Accepts + reads + writes.
+const int totalEvents = nConnections+2*nConnections*nMessages;
+
+/**
+ * Messages are numbered 0..nMessages.
+ * We count the total number of events, and the
+ * number of reads and writes for each message number.
+ */
+class TestResults : public Monitor {
+ public:
+ TestResults() : isShutdown(false), nEventsRemaining(totalEvents) {}
+
+ void countEvent() {
+ if (--nEventsRemaining == 0)
+ shutdown();
+ }
+
+ void countRead(int messageNo) {
+ ++reads[messageNo];
+ countEvent();
+ }
+
+ void countWrite(int messageNo) {
+ ++writes[messageNo];
+ countEvent();
+ }
+
+ void shutdown(const std::string& exceptionMsg = std::string()) {
+ ScopedLock lock(*this);
+ exception = exceptionMsg;
+ isShutdown = true;
+ notifyAll();
+ }
+
+ void wait() {
+ ScopedLock lock(*this);
+ Time deadline = now() + 10*TIME_SEC;
+ while (!isShutdown) {
+ CPPUNIT_ASSERT(Monitor::wait(deadline));
+ }
+ }
+
+ bool isShutdown;
+ std::string exception;
+ AtomicCount reads[nMessages];
+ AtomicCount writes[nMessages];
+ AtomicCount nEventsRemaining;
+};
+
+TestResults results;
+
+EventChannelThreads::shared_ptr threads;
+
+// Functor to wrap callbacks in try/catch.
+class SafeCallback {
+ public:
+ SafeCallback(Runnable& r) : callback(r.functor()) {}
+ SafeCallback(Event::Callback cb) : callback(cb) {}
+
+ void operator()() {
+ std::string exception;
+ try {
+ callback();
+ return;
+ }
+ catch (const std::exception& e) {
+ exception = e.what();
+ }
+ catch (...) {
+ exception = "Unknown exception.";
+ }
+ results.shutdown(exception);
+ }
+
+ private:
+ Event::Callback callback;
+};
+
+/** Repost an event N times. */
+class Repost {
+ public:
+ Repost(int n) : count (n) {}
+ virtual ~Repost() {}
+
+ void repost(Event* event) {
+ if (--count==0) {
+ delete event;
+ } else {
+ threads->postEvent(event);
+ }
+ }
+ private:
+ int count;
+};
+
+
+
+/** Repeating read event. */
+class TestReadEvent : public ReadEvent, public Runnable, private Repost {
+ public:
+ explicit TestReadEvent(int fd=-1) :
+ ReadEvent(fd, &value, sizeof(value), SafeCallback(*this)),
+ Repost(nMessages)
+ {}
+
+ void run() {
+ CPPUNIT_ASSERT_EQUAL(sizeof(value), getSize());
+ CPPUNIT_ASSERT(0 <= value);
+ CPPUNIT_ASSERT(value < nMessages);
+ results.countRead(value);
+ repost(this);
+ }
+
+ private:
+ int value;
+ ReadEvent original;
+};
+
+
+/** Fire and forget write event */
+class TestWriteEvent : public WriteEvent, public Runnable, private Repost {
+ public:
+ TestWriteEvent(int fd=-1) :
+ WriteEvent(fd, &value, sizeof(value), SafeCallback(*this)),
+ Repost(nMessages),
+ value(0)
+ {}
+
+ void run() {
+ CPPUNIT_ASSERT_EQUAL(sizeof(int), getSize());
+ results.countWrite(value++);
+ repost(this);
+ }
+
+ private:
+ int value;
+};
+
+/** Fire-and-forget Accept event, posts reads on the accepted connection. */
+class TestAcceptEvent : public AcceptEvent, public Runnable, private Repost {
+ public:
+ TestAcceptEvent(int fd=-1) :
+ AcceptEvent(fd, SafeCallback(*this)),
+ Repost(nConnections)
+ {}
+
+ void run() {
+ threads->postEvent(new TestReadEvent(getAcceptedDesscriptor()));
+ results.countEvent();
+ repost(this);
+ }
+};
+
+class EventChannelThreadsTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(EventChannelThreadsTest);
+ CPPUNIT_TEST(testThreads);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+
+ void setUp() {
+ threads = EventChannelThreads::create(EventChannel::create());
+ }
+
+ void tearDown() {
+ threads.reset();
+ }
+
+ void testThreads()
+ {
+ Socket listener = Socket::createTcp();
+ int port = listener.listen();
+
+ // Post looping accept events, will repost nConnections times.
+ // The accept event will automatically post read events.
+ threads->postEvent(new TestAcceptEvent(listener.fd()));
+
+ // Make connections.
+ Socket connections[nConnections];
+ for (int i = 0; i < nConnections; ++i) {
+ connections[i] = Socket::createTcp();
+ connections[i].connect("localhost", port);
+ }
+
+ // Post looping write events.
+ for (int i = 0; i < nConnections; ++i) {
+ threads->postEvent(new TestWriteEvent(connections[i].fd()));
+ }
+
+ // Wait for all events to be dispatched.
+ results.wait();
+
+ if (!results.exception.empty()) CPPUNIT_FAIL(results.exception);
+ CPPUNIT_ASSERT_EQUAL(0, int(results.nEventsRemaining));
+
+ // Expect a read and write for each messageNo from each connection.
+ for (int messageNo = 0; messageNo < nMessages; ++messageNo) {
+ CPPUNIT_ASSERT_EQUAL(nConnections, int(results.reads[messageNo]));
+ CPPUNIT_ASSERT_EQUAL(nConnections, int(results.writes[messageNo]));
+ }
+
+ threads->shutdown();
+ threads->join();
+ }
+};
+
+// Make this test suite a plugin.
+CPPUNIT_PLUGIN_IMPLEMENT();
+CPPUNIT_TEST_SUITE_REGISTRATION(EventChannelThreadsTest);
+
diff --git a/qpid/cpp/src/tests/ExchangeTest.cpp b/qpid/cpp/src/tests/ExchangeTest.cpp
new file mode 100644
index 0000000000..2904424d5c
--- /dev/null
+++ b/qpid/cpp/src/tests/ExchangeTest.cpp
@@ -0,0 +1,179 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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_test_plugin.h"
+#include <iostream>
+#include "qpid/framing/BasicGetBody.h"
+#include "MessageUtils.h"
+
+using boost::intrusive_ptr;
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::sys;
+using namespace qpid;
+
+class ExchangeTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(ExchangeTest);
+ CPPUNIT_TEST(testMe);
+ CPPUNIT_TEST(testIsBound);
+ CPPUNIT_TEST(testDeleteGetAndRedeclare);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+
+ void 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);
+
+ }
+
+ void 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");
+ fanout.bind(a, "", 0);
+ fanout.bind(b, "", 0);
+ fanout.bind(c, "", 0);
+
+ CPPUNIT_ASSERT(fanout.isBound(a, 0, 0));
+ CPPUNIT_ASSERT(fanout.isBound(b, 0, 0));
+ CPPUNIT_ASSERT(fanout.isBound(c, 0, 0));
+ CPPUNIT_ASSERT(!fanout.isBound(d, 0, 0));
+
+ DirectExchange direct("direct");
+ direct.bind(a, k1, 0);
+ direct.bind(a, k3, 0);
+ direct.bind(b, k2, 0);
+ direct.bind(c, k1, 0);
+
+ CPPUNIT_ASSERT(direct.isBound(a, 0, 0));
+ CPPUNIT_ASSERT(direct.isBound(a, &k1, 0));
+ CPPUNIT_ASSERT(direct.isBound(a, &k3, 0));
+ CPPUNIT_ASSERT(!direct.isBound(a, &k2, 0));
+ CPPUNIT_ASSERT(direct.isBound(b, 0, 0));
+ CPPUNIT_ASSERT(direct.isBound(b, &k2, 0));
+ CPPUNIT_ASSERT(direct.isBound(c, &k1, 0));
+ CPPUNIT_ASSERT(!direct.isBound(d, 0, 0));
+ CPPUNIT_ASSERT(!direct.isBound(d, &k1, 0));
+ CPPUNIT_ASSERT(!direct.isBound(d, &k2, 0));
+ CPPUNIT_ASSERT(!direct.isBound(d, &k3, 0));
+
+ TopicExchange topic("topic");
+ topic.bind(a, k1, 0);
+ topic.bind(a, k3, 0);
+ topic.bind(b, k2, 0);
+ topic.bind(c, k1, 0);
+
+ CPPUNIT_ASSERT(topic.isBound(a, 0, 0));
+ CPPUNIT_ASSERT(topic.isBound(a, &k1, 0));
+ CPPUNIT_ASSERT(topic.isBound(a, &k3, 0));
+ CPPUNIT_ASSERT(!topic.isBound(a, &k2, 0));
+ CPPUNIT_ASSERT(topic.isBound(b, 0, 0));
+ CPPUNIT_ASSERT(topic.isBound(b, &k2, 0));
+ CPPUNIT_ASSERT(topic.isBound(c, &k1, 0));
+ CPPUNIT_ASSERT(!topic.isBound(d, 0, 0));
+ CPPUNIT_ASSERT(!topic.isBound(d, &k1, 0));
+ CPPUNIT_ASSERT(!topic.isBound(d, &k2, 0));
+ CPPUNIT_ASSERT(!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);
+
+ CPPUNIT_ASSERT(headers.isBound(a, 0, 0));
+ CPPUNIT_ASSERT(headers.isBound(a, 0, &args1));
+ CPPUNIT_ASSERT(headers.isBound(a, 0, &args3));
+ CPPUNIT_ASSERT(!headers.isBound(a, 0, &args2));
+ CPPUNIT_ASSERT(headers.isBound(b, 0, 0));
+ CPPUNIT_ASSERT(headers.isBound(b, 0, &args2));
+ CPPUNIT_ASSERT(headers.isBound(c, 0, &args1));
+ CPPUNIT_ASSERT(!headers.isBound(d, 0, 0));
+ CPPUNIT_ASSERT(!headers.isBound(d, 0, &args1));
+ CPPUNIT_ASSERT(!headers.isBound(d, 0, &args2));
+ CPPUNIT_ASSERT(!headers.isBound(d, 0, &args3));
+ }
+
+ void testDeleteGetAndRedeclare() {
+ ExchangeRegistry exchanges;
+ exchanges.declare("my-exchange", "direct", false, FieldTable());
+ exchanges.destroy("my-exchange");
+ try {
+ exchanges.get("my-exchange");
+ } catch (const ChannelException&) {}
+ std::pair<Exchange::shared_ptr, bool> response = exchanges.declare("my-exchange", "direct", false, FieldTable());
+ CPPUNIT_ASSERT_EQUAL(string("direct"), response.first->getType());
+
+ }
+};
+
+// Make this test suite a plugin.
+CPPUNIT_PLUGIN_IMPLEMENT();
+CPPUNIT_TEST_SUITE_REGISTRATION(ExchangeTest);
diff --git a/qpid/cpp/src/tests/FieldTable.cpp b/qpid/cpp/src/tests/FieldTable.cpp
new file mode 100644
index 0000000000..db4c4906fa
--- /dev/null
+++ b/qpid/cpp/src/tests/FieldTable.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 <iostream>
+#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/FieldValue.h"
+
+#include "unit_test.h"
+
+using namespace qpid::framing;
+
+QPID_AUTO_TEST_SUITE(FieldTableTestSuite)
+
+BOOST_AUTO_TEST_CASE(testMe)
+{
+ FieldTable ft;
+ ft.setString("A", "BCDE");
+ BOOST_CHECK(StringValue("BCDE") == *ft.get("A"));
+
+ char buff[100];
+ Buffer wbuffer(buff, 100);
+ wbuffer.put(ft);
+
+ Buffer rbuffer(buff, 100);
+ FieldTable ft2;
+ rbuffer.get(ft2);
+ BOOST_CHECK(StringValue("BCDE") == *ft2.get("A"));
+
+}
+
+BOOST_AUTO_TEST_CASE(testAssignment)
+{
+ FieldTable a;
+ FieldTable b;
+
+ a.setString("A", "BBBB");
+ a.setInt("B", 1234);
+ b = a;
+ a.setString("A", "CCCC");
+
+ BOOST_CHECK(StringValue("CCCC") == *a.get("A"));
+ BOOST_CHECK(StringValue("BBBB") == *b.get("A"));
+ BOOST_CHECK_EQUAL(1234, a.getInt("B"));
+ BOOST_CHECK_EQUAL(1234, b.getInt("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.size()));
+ Buffer wbuffer(buff, c.size());
+ wbuffer.put(c);
+
+ Buffer rbuffer(buff, c.size());
+ rbuffer.get(d);
+ BOOST_CHECK_EQUAL(c, d);
+ BOOST_CHECK(StringValue("CCCC") == *c.get("A"));
+ BOOST_CHECK(IntegerValue(1234) == *c.get("B"));
+ }
+ BOOST_CHECK(StringValue("CCCC") == *d.get("A"));
+ BOOST_CHECK(IntegerValue(1234) == *d.get("B"));
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/FieldValue.cpp b/qpid/cpp/src/tests/FieldValue.cpp
new file mode 100644
index 0000000000..a820ae57bd
--- /dev/null
+++ b/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;
+
+StringValue s("abc");
+IntegerValue i(42);
+//DecimalValue d(1234,2);
+//FieldTableValue ft;
+//EmptyValue e;
+
+BOOST_AUTO_TEST_CASE(testStringValueEquals)
+{
+
+ BOOST_CHECK(StringValue("abc") == s);
+ BOOST_CHECK(StringValue("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);
+
+}
+
+BOOST_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
+BOOST_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);
+}
+
+BOOST_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/qpid/cpp/src/tests/Frame.cpp b/qpid/cpp/src/tests/Frame.cpp
new file mode 100644
index 0000000000..0484dc4b2a
--- /dev/null
+++ b/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;
+
+BOOST_AUTO_TEST_CASE(testContentBody) {
+ Frame f(42, AMQContentBody("foobar"));
+ AMQBody* body=f.getBody();
+ BOOST_CHECK(dynamic_cast<AMQContentBody*>(body));
+ Buffer b(f.size());
+ 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");
+}
+
+BOOST_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.size());
+ 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()));
+}
+
+BOOST_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/qpid/cpp/src/tests/FramingTest.cpp b/qpid/cpp/src/tests/FramingTest.cpp
new file mode 100644
index 0000000000..0c7adb2af8
--- /dev/null
+++ b/qpid/cpp/src/tests/FramingTest.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/client/Exchange.h"
+#include "qpid/client/Queue.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Connector.h"
+#include "qpid/framing/AMQP_HighestVersion.h"
+#include "qpid/framing/BasicGetOkBody.h"
+#include "qpid/framing/ConnectionRedirectBody.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 "qpid_test_plugin.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();
+}
+
+class FramingTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(FramingTest);
+ CPPUNIT_TEST(testBasicQosBody);
+ CPPUNIT_TEST(testConnectionSecureBody);
+ CPPUNIT_TEST(testConnectionRedirectBody);
+ CPPUNIT_TEST(testAccessRequestBody);
+ CPPUNIT_TEST(testBasicConsumeBody);
+ CPPUNIT_TEST(testConnectionRedirectBodyFrame);
+ CPPUNIT_TEST(testBasicConsumeOkBodyFrame);
+ CPPUNIT_TEST(testInlineContent);
+ CPPUNIT_TEST(testContentReference);
+ CPPUNIT_TEST(testContentValidation);
+ CPPUNIT_TEST_SUITE_END();
+
+ private:
+ char buffer[1024];
+ ProtocolVersion version;
+
+ public:
+
+ FramingTest() : version(highestProtocolVersion) {}
+
+ void testBasicQosBody()
+ {
+ Buffer wbuff(buffer, sizeof(buffer));
+ BasicQosBody in(version, 0xCAFEBABE, 0xABBA, true);
+ in.encode(wbuff);
+
+ Buffer rbuff(buffer, sizeof(buffer));
+ BasicQosBody out(version);
+ out.decode(rbuff);
+ CPPUNIT_ASSERT_EQUAL(tostring(in), tostring(out));
+ }
+
+ void testConnectionSecureBody()
+ {
+ 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);
+ CPPUNIT_ASSERT_EQUAL(tostring(in), tostring(out));
+ }
+
+ void testConnectionRedirectBody()
+ {
+ Buffer wbuff(buffer, sizeof(buffer));
+ std::string a = "hostA";
+ std::string b = "hostB";
+ ConnectionRedirectBody in(version, a, b);
+ in.encode(wbuff);
+
+ Buffer rbuff(buffer, sizeof(buffer));
+ ConnectionRedirectBody out(version);
+ out.decode(rbuff);
+ CPPUNIT_ASSERT_EQUAL(tostring(in), tostring(out));
+ }
+
+ void testAccessRequestBody()
+ {
+ Buffer wbuff(buffer, sizeof(buffer));
+ std::string s = "text";
+ AccessRequestBody in(version, s, true, false, true, false, true);
+ in.encode(wbuff);
+
+ Buffer rbuff(buffer, sizeof(buffer));
+ AccessRequestBody out(version);
+ out.decode(rbuff);
+ CPPUNIT_ASSERT_EQUAL(tostring(in), tostring(out));
+ }
+
+ void testBasicConsumeBody()
+ {
+ Buffer wbuff(buffer, sizeof(buffer));
+ std::string q = "queue";
+ std::string t = "tag";
+ BasicConsumeBody in(version, 0, q, t, false, true, false, false,
+ FieldTable());
+ in.encode(wbuff);
+
+ Buffer rbuff(buffer, sizeof(buffer));
+ BasicConsumeBody out(version);
+ out.decode(rbuff);
+ CPPUNIT_ASSERT_EQUAL(tostring(in), tostring(out));
+ }
+
+
+ void testConnectionRedirectBodyFrame()
+ {
+ Buffer wbuff(buffer, sizeof(buffer));
+ std::string a = "hostA";
+ std::string b = "hostB";
+ AMQFrame in(in_place<ConnectionRedirectBody>(version, a, b));
+ in.setChannel(999);
+ in.encode(wbuff);
+
+ Buffer rbuff(buffer, sizeof(buffer));
+ AMQFrame out;
+ out.decode(rbuff);
+ CPPUNIT_ASSERT_EQUAL(tostring(in), tostring(out));
+ }
+
+ void testBasicConsumeOkBodyFrame()
+ {
+ Buffer wbuff(buffer, sizeof(buffer));
+ std::string s = "hostA";
+ AMQFrame in(in_place<BasicConsumeOkBody>(version, s));
+ in.setChannel(999);
+ in.encode(wbuff);
+
+ Buffer rbuff(buffer, sizeof(buffer));
+ AMQFrame out;
+ out.decode(rbuff);
+ CPPUNIT_ASSERT_EQUAL(tostring(in), tostring(out));
+ }
+
+ void testInlineContent() {
+ Buffer wbuff(buffer, sizeof(buffer));
+ Content content(INLINE, "MyData");
+ CPPUNIT_ASSERT(content.isInline());
+ content.encode(wbuff);
+
+ Buffer rbuff(buffer, sizeof(buffer));
+ Content recovered;
+ recovered.decode(rbuff);
+ CPPUNIT_ASSERT(recovered.isInline());
+ CPPUNIT_ASSERT_EQUAL(content.getValue(), recovered.getValue());
+ }
+
+ void testContentReference() {
+ Buffer wbuff(buffer, sizeof(buffer));
+ Content content(REFERENCE, "MyRef");
+ CPPUNIT_ASSERT(content.isReference());
+ content.encode(wbuff);
+
+ Buffer rbuff(buffer, sizeof(buffer));
+ Content recovered;
+ recovered.decode(rbuff);
+ CPPUNIT_ASSERT(recovered.isReference());
+ CPPUNIT_ASSERT_EQUAL(content.getValue(), recovered.getValue());
+ }
+
+ void testContentValidation() {
+ try {
+ Content content(REFERENCE, "");
+ CPPUNIT_ASSERT(false);//fail, expected exception
+ } catch (const InvalidArgumentException& e) {}
+
+ try {
+ Content content(2, "Blah");
+ CPPUNIT_ASSERT(false);//fail, expected exception
+ } catch (const SyntaxErrorException& e) {}
+
+ try {
+ Buffer wbuff(buffer, sizeof(buffer));
+ wbuff.putOctet(2);
+ wbuff.putLongString("blah, blah");
+
+ Buffer rbuff(buffer, sizeof(buffer));
+ Content content;
+ content.decode(rbuff);
+ CPPUNIT_FAIL("Expected exception");
+ } catch (Exception& e) {}
+
+ }
+
+ };
+
+
+// Make this test suite a plugin.
+CPPUNIT_PLUGIN_IMPLEMENT();
+CPPUNIT_TEST_SUITE_REGISTRATION(FramingTest);
+
+
+
diff --git a/qpid/cpp/src/tests/HeaderTest.cpp b/qpid/cpp/src/tests/HeaderTest.cpp
new file mode 100644
index 0000000000..9e2bddb4de
--- /dev/null
+++ b/qpid/cpp/src/tests/HeaderTest.cpp
@@ -0,0 +1,126 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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 "qpid_test_plugin.h"
+
+using namespace qpid::framing;
+using namespace std;
+
+class HeaderTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(HeaderTest);
+ CPPUNIT_TEST(testGenericProperties);
+ CPPUNIT_TEST(testMessageProperties);
+ CPPUNIT_TEST(testDeliveryProperies);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+
+ void 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.size());
+ MessageProperties* props =
+ body2.get<MessageProperties>(true);
+ CPPUNIT_ASSERT_EQUAL(
+ string("BCDE"),
+ props->getApplicationHeaders().get("A")->get<string>());
+ }
+
+ void testMessageProperties() {
+ AMQFrame out(in_place<AMQHeaderBody>());
+ MessageProperties* props1 =
+ out.castBody<AMQHeaderBody>()->get<MessageProperties>(true);
+
+ props1->setContentLength(42);
+ props1->setMessageId("messageId");
+ props1->setCorrelationId("correlationId");
+ props1->setReplyTo(ReplyTo("ex","key"));
+ props1->setContentType("contentType");
+ props1->setContentEncoding("contentEncoding");
+ props1->setType("type");
+ props1->setUserId("userId");
+ props1->setAppId("appId");
+ props1->setTransactionId("transactionId");
+ props1->setSecurityToken("securityToken");
+
+ 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);
+
+ CPPUNIT_ASSERT_EQUAL(props1->getContentLength(), props2->getContentLength());
+ CPPUNIT_ASSERT_EQUAL(props1->getMessageId(), props2->getMessageId());
+ CPPUNIT_ASSERT_EQUAL(props1->getCorrelationId(), props2->getCorrelationId());
+ CPPUNIT_ASSERT_EQUAL(props1->getContentType(), props2->getContentType());
+ CPPUNIT_ASSERT_EQUAL(props1->getContentEncoding(), props2->getContentEncoding());
+ CPPUNIT_ASSERT_EQUAL(props1->getType(), props2->getType());
+ CPPUNIT_ASSERT_EQUAL(props1->getUserId(), props2->getUserId());
+ CPPUNIT_ASSERT_EQUAL(props1->getAppId(), props2->getAppId());
+ CPPUNIT_ASSERT_EQUAL(props1->getTransactionId(), props2->getTransactionId());
+ CPPUNIT_ASSERT_EQUAL(props1->getSecurityToken(), props2->getSecurityToken());
+
+ }
+
+ void 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);
+
+ CPPUNIT_ASSERT(props2->getDiscardUnroutable());
+ CPPUNIT_ASSERT_EQUAL(string("foo"), props2->getExchange());
+ CPPUNIT_ASSERT(!props2->hasTimestamp());
+ }
+
+};
+
+// Make this test suite a plugin.
+CPPUNIT_PLUGIN_IMPLEMENT();
+CPPUNIT_TEST_SUITE_REGISTRATION(HeaderTest);
+
diff --git a/qpid/cpp/src/tests/HeadersExchangeTest.cpp b/qpid/cpp/src/tests/HeadersExchangeTest.cpp
new file mode 100644
index 0000000000..f07f238ee4
--- /dev/null
+++ b/qpid/cpp/src/tests/HeadersExchangeTest.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/Exception.h"
+#include "qpid/broker/HeadersExchange.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/FieldValue.h"
+#include "qpid_test_plugin.h"
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+class HeadersExchangeTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(HeadersExchangeTest);
+ CPPUNIT_TEST(testMatchAll);
+ CPPUNIT_TEST(testMatchAny);
+ CPPUNIT_TEST(testMatchEmptyValue);
+ CPPUNIT_TEST(testMatchEmptyArgs);
+ CPPUNIT_TEST(testMatchNoXMatch);
+ CPPUNIT_TEST(testBindNoXMatch);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+
+ void 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);
+ CPPUNIT_ASSERT(HeadersExchange::match(b, m));
+
+ // Ignore extras.
+ m.setString("extra", "x");
+ CPPUNIT_ASSERT(HeadersExchange::match(b, m));
+
+ // Fail mismatch, wrong value.
+ m.setString("foo", "NotFoo");
+ CPPUNIT_ASSERT(!HeadersExchange::match(b, m));
+
+ // Fail mismatch, missing value
+ n.setInt("n", 42);
+ n.setString("extra", "x");
+ CPPUNIT_ASSERT(!HeadersExchange::match(b, n));
+ }
+
+ void testMatchAny()
+ {
+ FieldTable b, m, n;
+ b.setString("x-match", "any");
+ b.setString("foo", "FOO");
+ b.setInt("n", 42);
+ m.setString("foo", "FOO");
+ CPPUNIT_ASSERT(!HeadersExchange::match(b, n));
+ CPPUNIT_ASSERT(HeadersExchange::match(b, m));
+ m.setInt("n", 42);
+ CPPUNIT_ASSERT(HeadersExchange::match(b, m));
+ }
+
+ void testMatchEmptyValue()
+ {
+ FieldTable b, m;
+ b.setString("x-match", "all");
+ b.set("foo", FieldTable::ValuePtr());
+ b.set("n", FieldTable::ValuePtr());
+ CPPUNIT_ASSERT(!HeadersExchange::match(b, m));
+ m.setString("foo", "blah");
+ m.setInt("n", 123);
+ }
+
+ void testMatchEmptyArgs()
+ {
+ FieldTable b, m;
+ m.setString("foo", "FOO");
+
+ b.setString("x-match", "all");
+ CPPUNIT_ASSERT(HeadersExchange::match(b, m));
+ b.setString("x-match", "any");
+ CPPUNIT_ASSERT(!HeadersExchange::match(b, m));
+ }
+
+
+ void testMatchNoXMatch()
+ {
+ FieldTable b, m;
+ b.setString("foo", "FOO");
+ m.setString("foo", "FOO");
+ CPPUNIT_ASSERT(!HeadersExchange::match(b, m));
+ }
+
+ void 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
+ }
+ }
+
+
+};
+
+// make this test suite a plugin.
+CPPUNIT_PLUGIN_IMPLEMENT();
+CPPUNIT_TEST_SUITE_REGISTRATION(HeadersExchangeTest);
diff --git a/qpid/cpp/src/tests/IList.cpp b/qpid/cpp/src/tests/IList.cpp
new file mode 100644
index 0000000000..2e872d0e05
--- /dev/null
+++ b/qpid/cpp/src/tests/IList.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 "qpid/IList.h"
+#include "unit_test.h"
+#include "test_tools.h"
+#include <boost/assign/list_of.hpp>
+#include <vector>
+
+QPID_AUTO_TEST_SUITE(IListTestSuite)
+
+using namespace qpid;
+using namespace std;
+using boost::assign::list_of;
+
+// Comparison, op== and << for ILists in qpid namespace for template lookup.
+
+template <class T, class S> bool operator==(const IList<T>& a, const S& b) { return seqEqual(a, b); }
+template <class T> ostream& operator<<(std::ostream& o, const IList<T>& l) { return seqPrint(o, l); }
+template <class T>
+ostream& operator<<(ostream& o, typename IList<T>::iterator i) {
+ return i? o << "(nil)" : o << *i;
+}
+
+struct IListFixture {
+ struct Node : public IListNode<Node*> {
+ char value;
+ Node(char c) { value=c; }
+ bool operator==(const Node& n) const { return value == n.value; }
+ };
+ typedef IList<Node> List;
+ Node a, b, c, d, e;
+ IListFixture() :a('a'),b('b'),c('c'),d('d'),e('e') {}
+};
+
+ostream& operator<<(ostream& o, const IListFixture::Node& n) { return o << n.value; }
+
+BOOST_FIXTURE_TEST_CASE(IList_default_ctor, IListFixture) {
+ List l;
+ BOOST_CHECK(l.empty());
+ BOOST_CHECK(l.begin() == l.end());
+ BOOST_CHECK_EQUAL(0u, l.size());
+}
+
+BOOST_FIXTURE_TEST_CASE(IList_push_front, IListFixture) {
+ List l;
+ l.push_front(&a);
+ BOOST_CHECK_EQUAL(1u, l.size());
+ BOOST_CHECK_EQUAL(l, list_of(a));
+ l.push_front(&b);
+ BOOST_CHECK_EQUAL(2u, l.size());
+ BOOST_CHECK_EQUAL(l, list_of(b)(a));
+}
+
+BOOST_FIXTURE_TEST_CASE(IList_push_back, IListFixture) {
+ List l;
+ l.push_back(&a);
+ BOOST_CHECK_EQUAL(1u, l.size());
+ BOOST_CHECK_EQUAL(l, list_of(a));
+ l.push_back(&b);
+ BOOST_CHECK_EQUAL(2u, l.size());
+ BOOST_CHECK_EQUAL(l, list_of(a)(b));
+}
+
+BOOST_FIXTURE_TEST_CASE(IList_insert, IListFixture) {
+ List l;
+ List::iterator i(l.begin());
+ i = l.insert(i, &a);
+ BOOST_CHECK_EQUAL(l, list_of(a));
+ BOOST_CHECK(i == l.begin());
+
+ i = l.insert(i, &b);
+ BOOST_CHECK_EQUAL(l, list_of(b)(a));
+ BOOST_CHECK(i == l.begin());
+
+ i++;
+ BOOST_CHECK_EQUAL(*i, a);
+ i = l.insert(i, &c);
+ BOOST_CHECK_EQUAL(l, list_of(b)(c)(a));
+ BOOST_CHECK_EQUAL(*i, c);
+
+ i = l.insert(i, &d);
+ BOOST_CHECK_EQUAL(l, list_of(b)(d)(c)(a));
+ BOOST_CHECK_EQUAL(*i, d);
+}
+
+BOOST_FIXTURE_TEST_CASE(IList_iterator_test, IListFixture) {
+ List l;
+ l.push_back(&a);
+ l.push_back(&b);
+
+ List::iterator i = l.begin();
+ BOOST_CHECK_EQUAL(*i, a);
+ BOOST_CHECK_EQUAL(static_cast<Node*>(i), &a);
+ List::const_iterator ci = i;
+ BOOST_CHECK_EQUAL(static_cast<const Node*>(ci), &a);
+
+ i++;
+ BOOST_CHECK_EQUAL(*i, b);
+ BOOST_CHECK_EQUAL(static_cast<Node*>(i), &b);
+ i++;
+ BOOST_CHECK(i == l.end());
+}
+
+BOOST_FIXTURE_TEST_CASE(IList_pop_front, IListFixture) {
+ List l;
+ l.push_back(&a);
+ l.push_back(&b);
+ BOOST_CHECK_EQUAL(l, list_of(a)(b));
+ l.pop_front();
+ BOOST_CHECK_EQUAL(l, list_of(b));
+ l.pop_front();
+ BOOST_CHECK(l.empty());
+}
+
+BOOST_FIXTURE_TEST_CASE(IList_pop_back, IListFixture) {
+ List l;
+ l.push_back(&a);
+ l.push_back(&b);
+ l.pop_back();
+ BOOST_CHECK_EQUAL(l, list_of(a));
+ l.pop_back();
+ BOOST_CHECK(l.empty());
+}
+
+BOOST_FIXTURE_TEST_CASE(IList_erase, IListFixture) {
+ List l;
+ l.push_back(&a);
+ l.push_back(&b);
+ l.push_back(&c);
+
+ List::iterator i=l.begin();
+ i++;
+ l.erase(i);
+ BOOST_CHECK_EQUAL(l, list_of(a)(c));
+
+ i=l.begin();
+ i++;
+ l.erase(i);
+ BOOST_CHECK_EQUAL(l, list_of(a));
+
+ l.erase(l.begin());
+ BOOST_CHECK(l.empty());
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
diff --git a/qpid/cpp/src/tests/ISList.cpp b/qpid/cpp/src/tests/ISList.cpp
new file mode 100644
index 0000000000..81301e3732
--- /dev/null
+++ b/qpid/cpp/src/tests/ISList.cpp
@@ -0,0 +1,209 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/ISList.h"
+#include "qpid/RefCounted.h"
+#include "unit_test.h"
+#include "test_tools.h"
+#include <boost/assign/list_of.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/intrusive_ptr.hpp>
+#include <vector>
+
+QPID_AUTO_TEST_SUITE(ISListTestSuite)
+
+using namespace qpid;
+using namespace std;
+using boost::assign::list_of;
+using boost::intrusive_ptr;
+
+// Comparison, op== and << for ILists in qpid namespace for template lookup.
+
+template <class T, class S> bool operator==(const ISList<T>& a, const S& b) { return seqEqual(a, b); }
+template <class T> ostream& operator<<(std::ostream& o, const ISList<T>& l) { return seqPrint(o, l); }
+template <class T>
+ostream& operator<<(ostream& o, typename ISList<T>::iterator i) {
+ return i? o << "(nil)" : o << *i;
+}
+
+struct NodeBase {
+ static int instances;
+ char value;
+
+ NodeBase(char c) { value=c; ++instances; }
+ NodeBase(const NodeBase& n) { value=n.value; ++instances; }
+ ~NodeBase() { --instances; }
+ bool operator==(const NodeBase& n) const { return value == n.value; }
+};
+
+int NodeBase::instances = 0;
+
+ostream& operator<<(ostream& o, const NodeBase& n) { return o << n.value; }
+
+struct Fixture {
+ struct Node : public NodeBase, public ISListNode<Node*> {
+ Node(char c) : NodeBase(c) {}
+ };
+ typedef ISList<Node> List;
+ Node a, b, c, d, e;
+ List l;
+ Fixture() :a('a'),b('b'),c('c'),d('d'),e('e') {}
+};
+
+BOOST_FIXTURE_TEST_CASE(default_ctor, Fixture) {
+ BOOST_CHECK(l.empty());
+ BOOST_CHECK(l.begin() == l.end());
+ BOOST_CHECK_EQUAL(0u, l.size());
+}
+
+BOOST_FIXTURE_TEST_CASE(push_front, Fixture) {
+ l.push_front(&a);
+ BOOST_CHECK_EQUAL(1u, l.size());
+ BOOST_CHECK_EQUAL(l, list_of(a));
+ l.push_front(&b);
+ BOOST_CHECK_EQUAL(2u, l.size());
+ BOOST_CHECK_EQUAL(l, list_of(b)(a));
+}
+
+BOOST_FIXTURE_TEST_CASE(push_back, Fixture) {
+ l.push_back(&a);
+ BOOST_CHECK_EQUAL(1u, l.size());
+ BOOST_CHECK_EQUAL(l, list_of(a));
+ l.push_back(&b);
+ BOOST_CHECK_EQUAL(2u, l.size());
+ BOOST_CHECK_EQUAL(l, list_of(a)(b));
+}
+
+BOOST_FIXTURE_TEST_CASE(insert, Fixture) {
+ List::iterator i(l.begin());
+ i = l.insert(i, &a);
+ BOOST_CHECK_EQUAL(l, list_of(a));
+ BOOST_CHECK(i == l.begin());
+
+ i = l.insert(i, &b);
+ BOOST_CHECK_EQUAL(l, list_of(b)(a));
+ BOOST_CHECK(i == l.begin());
+
+ i++;
+ BOOST_CHECK_EQUAL(*i, a);
+ i = l.insert(i, &c);
+ BOOST_CHECK_EQUAL(l, list_of(b)(c)(a));
+ BOOST_CHECK_EQUAL(*i, c);
+
+ i = l.insert(i, &d);
+ BOOST_CHECK_EQUAL(l, list_of(b)(d)(c)(a));
+ BOOST_CHECK_EQUAL(*i, d);
+}
+
+BOOST_FIXTURE_TEST_CASE(iterator_test, Fixture) {
+ l.push_back(&a);
+ l.push_back(&b);
+
+ List::iterator i = l.begin();
+ BOOST_CHECK_EQUAL(*i, a);
+ BOOST_CHECK_EQUAL(static_cast<Node*>(i), &a);
+ List::const_iterator ci = i;
+ BOOST_CHECK_EQUAL(static_cast<const Node*>(ci), &a);
+
+ i++;
+ BOOST_CHECK_EQUAL(*i, b);
+ BOOST_CHECK_EQUAL(static_cast<Node*>(i), &b);
+ i++;
+ BOOST_CHECK(i == l.end());
+}
+
+BOOST_FIXTURE_TEST_CASE(pop_front, Fixture) {
+ l.push_back(&a);
+ l.push_back(&b);
+ l.pop_front();
+ BOOST_CHECK_EQUAL(l, list_of(b));
+ l.pop_front();
+ BOOST_CHECK(l.empty());
+}
+
+BOOST_FIXTURE_TEST_CASE(erase, Fixture) {
+ l.push_back(&a);
+ l.push_back(&b);
+ l.push_back(&c);
+
+ List::iterator i=l.begin();
+ i++;
+ l.erase(i);
+ BOOST_CHECK_EQUAL(l, list_of(a)(c));
+
+ i=l.begin();
+ i++;
+ l.erase(i);
+ BOOST_CHECK_EQUAL(l, list_of(a));
+
+ l.erase(l.begin());
+ BOOST_CHECK(l.empty());
+}
+
+
+// ================ Test smart pointer types.
+
+template <class Node> void smart_pointer_test() {
+ typedef typename Node::pointer pointer;
+ typedef ISList<Node> List;
+ List l;
+
+ BOOST_CHECK_EQUAL(0, NodeBase::instances);
+ l.push_back(pointer(new Node()));
+ l.push_back(pointer(new Node()));
+ BOOST_CHECK_EQUAL(2, NodeBase::instances); // maintains a reference.
+
+ pointer p = l.begin();
+ l.pop_front();
+ BOOST_CHECK_EQUAL(2, NodeBase::instances); // transfers ownership.
+ p = pointer();
+ BOOST_CHECK_EQUAL(1, NodeBase::instances);
+
+ l.clear();
+ BOOST_CHECK_EQUAL(0, NodeBase::instances);
+ { // Dtor cleans up
+ List ll;
+ ll.push_back(pointer(new Node()));
+ BOOST_CHECK_EQUAL(1, NodeBase::instances);
+ }
+ BOOST_CHECK_EQUAL(0, NodeBase::instances);
+}
+
+struct IntrusiveNode : public NodeBase, public RefCounted,
+ public ISListNode<intrusive_ptr<IntrusiveNode> >
+{
+ IntrusiveNode() : NodeBase(0) {}
+};
+
+
+BOOST_AUTO_TEST_CASE(intrusive_ptr_test) {
+ smart_pointer_test<IntrusiveNode>();
+}
+
+
+struct SharedNode : public NodeBase, public ISListNode<boost::shared_ptr<SharedNode> > {
+ SharedNode() : NodeBase(0) {}
+};
+
+BOOST_AUTO_TEST_CASE(shared_ptr_test) {
+ smart_pointer_test<SharedNode>();
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/IncompleteMessageList.cpp b/qpid/cpp/src/tests/IncompleteMessageList.cpp
new file mode 100644
index 0000000000..65cca4a628
--- /dev/null
+++ b/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();
+ }
+};
+
+BOOST_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);
+}
+
+BOOST_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();
+ }
+};
+
+BOOST_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/qpid/cpp/src/tests/InlineVector.cpp b/qpid/cpp/src/tests/InlineVector.cpp
new file mode 100644
index 0000000000..d1b3ebf7de
--- /dev/null
+++ b/qpid/cpp/src/tests/InlineVector.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 "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 (char*)&v <= (char*)v.data() &&
+ (char*)v.data() < (char*)&v+sizeof(v);
+}
+
+BOOST_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));
+ }
+}
+
+BOOST_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_EQUAL(v.size(), 4u);
+ BOOST_CHECK(!isInline(v));
+}
+
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/Makefile.am b/qpid/cpp/src/tests/Makefile.am
new file mode 100644
index 0000000000..7eddd9932e
--- /dev/null
+++ b/qpid/cpp/src/tests/Makefile.am
@@ -0,0 +1,182 @@
+AM_CXXFLAGS = $(WARNING_CFLAGS) $(CPPUNIT_CXXFLAGS) $(APR_CXXFLAGS) -DBOOST_TEST_DYN_LINK
+INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../gen -I$(top_builddir)/src/gen
+
+abs_builddir=@abs_builddir@
+extra_libs = $(CPPUNIT_LIBS)
+lib_client = $(abs_builddir)/../libqpidclient.la
+lib_common = $(abs_builddir)/../libqpidcommon.la
+lib_broker = $(abs_builddir)/../libqpidbroker.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)
+unit_test_SOURCES= unit_test.cpp unit_test.h \
+ BrokerFixture.h SocketProxy.h \
+ exception_test.cpp \
+ RefCounted.cpp \
+ SessionState.cpp Blob.cpp logging.cpp \
+ Url.cpp Uuid.cpp \
+ Shlib.cpp FieldValue.cpp FieldTable.cpp Array.cpp \
+ InlineVector.cpp \
+ ISList.cpp IList.cpp \
+ ClientSessionTest.cpp \
+ SequenceSet.cpp \
+ amqp_0_10/serialize.cpp \
+ amqp_0_10/ProxyTemplate.cpp \
+ amqp_0_10/apply.cpp \
+ IncompleteMessageList.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
+
+#
+# Other test programs
+#
+check_PROGRAMS+=perftest
+perftest_SOURCES=perftest.cpp test_tools.h TestOptions.h
+perftest_LDADD=$(lib_client)
+
+check_PROGRAMS+=txtest
+txtest_SOURCES=txtest.cpp TestOptions.h
+txtest_LDADD=$(lib_client)
+
+check_PROGRAMS+=latencytest
+latencytest_SOURCES=latencytest.cpp TestOptions.h
+latencytest_LDADD=$(lib_client)
+
+# NB: CppUnit test libraries below will be migrated to boost test programs.
+#
+
+# cppunit tests
+broker_unit_tests = \
+ AccumulatedAckTest \
+ DtxWorkRecordTest \
+ DeliveryRecordTest \
+ ExchangeTest \
+ HeadersExchangeTest \
+ MessageTest \
+ QueueRegistryTest \
+ QueueTest \
+ QueuePolicyTest \
+ TimerTest \
+ TopicExchangeTest \
+ TxAckTest \
+ TxBufferTest \
+ TxPublishTest \
+ MessageBuilderTest
+
+#client_unit_tests = \
+# ClientChannelTest
+
+framing_unit_tests = \
+ FramingTest \
+ HeaderTest \
+ SequenceNumberTest
+
+posix_unit_tests = \
+ EventChannelTest \
+ EventChannelThreadsTest
+
+unit_tests = \
+ $(broker_unit_tests) \
+ $(client_unit_tests) \
+ $(framing_unit_tests) \
+ $(misc_unit_tests)
+
+# Executables for client tests
+
+testprogs= \
+ client_test \
+ topic_listener \
+ topic_publisher
+# echo_service
+
+check_PROGRAMS += $(testprogs) interop_runner
+
+TESTS_ENVIRONMENT = VALGRIND=$(VALGRIND) srcdir=$(srcdir) QPID_DATA_DIR= $(srcdir)/run_test
+
+system_tests = client_test quick_perftest quick_topictest
+TESTS += run-unit-tests start_broker $(system_tests) python_tests stop_broker run_federation_tests
+
+EXTRA_DIST += \
+ run_test vg_check \
+ run-unit-tests start_broker python_tests stop_broker \
+ quick_topictest \
+ quick_perftest \
+ topictest \
+ run_federation_tests \
+ .valgrind.supp \
+ .valgrindrc \
+ MessageUtils.h \
+ MockConnectionInputHandler.h \
+ TxMocks.h \
+ qpid_test_plugin.h
+
+include gen.mk
+
+check_LTLIBRARIES += libdlclose_noop.la
+libdlclose_noop_la_LDFLAGS = -module -rpath $(abs_builddir)
+libdlclose_noop_la_SOURCES = dlclose_noop.c
+
+gen.mk: Makefile.am
+ ( \
+ for i in $(testprogs); do \
+ echo $${i}_SOURCES = $$i.cpp; \
+ echo $${i}_LDADD = '$$(lib_client) $$(lib_common) $$(extra_libs)'; \
+ done; \
+ libs=; \
+ for i in $(unit_tests); do \
+ echo "check_LTLIBRARIES +=$${i}.la"; \
+ echo $${i}_la_SOURCES = $$i.cpp; \
+ echo $${i}_la_LIBADD = '$$(lib_common) $$(lib_client)'; \
+ echo $${i}_la_LIBADD += '$$(lib_broker) $$(extra_libs)'; \
+ echo $${i}_la_LDFLAGS = "-module -rpath `pwd`"; \
+ done; \
+ ) \
+ > $@-t
+ mv $@-t $@
+
+CLEANFILES+=valgrind.out *.log *.vglog dummy_test $(unit_wrappers)
+MAINTAINERCLEANFILES=gen.mk
+
+interop_runner_SOURCES = \
+ interop_runner.cpp \
+ SimpleTestCaseBase.cpp \
+ BasicP2PTest.cpp \
+ BasicPubSubTest.cpp \
+ SimpleTestCaseBase.h \
+ BasicP2PTest.h \
+ BasicPubSubTest.h \
+ TestCase.h \
+ TestOptions.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
+EXTRA_DIST+=$(LONG_TESTS) run_perftest
+check-long:
+ $(MAKE) check TESTS="start_broker $(LONG_TESTS) stop_broker" VALGRIND=
diff --git a/qpid/cpp/src/tests/MessageBuilderTest.cpp b/qpid/cpp/src/tests/MessageBuilderTest.cpp
new file mode 100644
index 0000000000..092e02cc2f
--- /dev/null
+++ b/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/TypeFilter.h"
+#include "qpid_test_plugin.h"
+#include <list>
+
+using namespace boost;
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+class MessageBuilderTest : public CppUnit::TestCase
+{
+ 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)
+ {
+ CPPUNIT_ASSERT_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(intrusive_ptr<PersistableMessage>& msg)
+ {
+ checkExpectation(STAGE);
+ CPPUNIT_ASSERT_EQUAL(expectedMsg, msg);
+ msg->setPersistenceId(++id);
+ }
+
+ void appendContent(intrusive_ptr<const PersistableMessage>& msg, const string& data)
+ {
+ checkExpectation(APPEND);
+ CPPUNIT_ASSERT_EQUAL(static_pointer_cast<const PersistableMessage>(expectedMsg), msg);
+ CPPUNIT_ASSERT_EQUAL(expectedData, data);
+ }
+
+ bool expectationsMet()
+ {
+ return ops.empty();
+ }
+ };
+
+ CPPUNIT_TEST_SUITE(MessageBuilderTest);
+ CPPUNIT_TEST(testHeaderOnly);
+ CPPUNIT_TEST(test1ContentFrame);
+ CPPUNIT_TEST(test2ContentFrames);
+ CPPUNIT_TEST(testStaging);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+
+ void testHeaderOnly(){
+ MessageBuilder builder(0, 0);
+ builder.start(SequenceNumber());
+
+ std::string exchange("builder-exchange");
+ std::string key("builder-exchange");
+
+ AMQFrame method(in_place<MessageTransferBody>(
+ ProtocolVersion(), 0, 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);
+
+ CPPUNIT_ASSERT(builder.getMessage());
+ CPPUNIT_ASSERT_EQUAL(exchange, builder.getMessage()->getExchangeName());
+ CPPUNIT_ASSERT_EQUAL(key, builder.getMessage()->getRoutingKey());
+ CPPUNIT_ASSERT(builder.getMessage()->getFrames().isComplete());
+ }
+
+ void 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(), 0, 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);
+ CPPUNIT_ASSERT(builder.getMessage());
+ CPPUNIT_ASSERT(!builder.getMessage()->getFrames().isComplete());
+
+ builder.handle(header);
+ CPPUNIT_ASSERT(builder.getMessage());
+ CPPUNIT_ASSERT(!builder.getMessage()->getFrames().isComplete());
+
+ builder.handle(content);
+ CPPUNIT_ASSERT(builder.getMessage());
+ CPPUNIT_ASSERT(builder.getMessage()->getFrames().isComplete());
+ }
+
+ void 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(), 0, 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);
+ CPPUNIT_ASSERT(builder.getMessage());
+ CPPUNIT_ASSERT(!builder.getMessage()->getFrames().isComplete());
+
+ builder.handle(content2);
+ CPPUNIT_ASSERT(builder.getMessage());
+ CPPUNIT_ASSERT(builder.getMessage()->getFrames().isComplete());
+ }
+
+ void 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(), 0, 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);
+ CPPUNIT_ASSERT(store.expectationsMet());
+ CPPUNIT_ASSERT_EQUAL((uint64_t) 1, builder.getMessage()->getPersistenceId());
+
+ store.expectAppendContent(*builder.getMessage(), data2);
+ builder.handle(content2);
+ CPPUNIT_ASSERT(store.expectationsMet());
+
+ //were the content frames dropped?
+ CPPUNIT_ASSERT_EQUAL((uint64_t) 0, builder.getMessage()->contentSize());
+ }
+};
+
+// Make this test suite a plugin.
+CPPUNIT_PLUGIN_IMPLEMENT();
+CPPUNIT_TEST_SUITE_REGISTRATION(MessageBuilderTest);
diff --git a/qpid/cpp/src/tests/MessageTest.cpp b/qpid/cpp/src/tests/MessageTest.cpp
new file mode 100644
index 0000000000..a19080e1ce
--- /dev/null
+++ b/qpid/cpp/src/tests/MessageTest.cpp
@@ -0,0 +1,97 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/FieldValue.h"
+
+#include "qpid_test_plugin.h"
+
+#include <iostream>
+
+using namespace boost;
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+
+class MessageTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(MessageTest);
+ CPPUNIT_TEST(testEncodeDecode);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+
+ void testEncodeDecode()
+ {
+ string exchange = "MyExchange";
+ string routingKey = "MyRoutingKey";
+ string messageId = "MyMessage";
+ string data1("abcdefg");
+ string data2("hijklmn");
+
+ intrusive_ptr<Message> msg(new Message());
+
+ AMQFrame method(in_place<MessageTransferBody>(
+ ProtocolVersion(), 0, 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);
+ CPPUNIT_ASSERT(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);
+ CPPUNIT_ASSERT_EQUAL(exchange, msg->getExchangeName());
+ CPPUNIT_ASSERT_EQUAL(routingKey, msg->getRoutingKey());
+ CPPUNIT_ASSERT_EQUAL((uint64_t) data1.size() + data2.size(), msg->contentSize());
+ CPPUNIT_ASSERT_EQUAL((uint64_t) data1.size() + data2.size(), msg->getProperties<MessageProperties>()->getContentLength());
+ CPPUNIT_ASSERT_EQUAL(messageId, msg->getProperties<MessageProperties>()->getMessageId());
+ CPPUNIT_ASSERT(StringValue("xyz") == *msg->getProperties<MessageProperties>()->getApplicationHeaders().get("abc"));
+ CPPUNIT_ASSERT_EQUAL((uint8_t) PERSISTENT, msg->getProperties<DeliveryProperties>()->getDeliveryMode());
+ CPPUNIT_ASSERT(msg->isPersistent());
+ }
+};
+
+// Make this test suite a plugin.
+CPPUNIT_PLUGIN_IMPLEMENT();
+CPPUNIT_TEST_SUITE_REGISTRATION(MessageTest);
+
diff --git a/qpid/cpp/src/tests/MessageUtils.h b/qpid/cpp/src/tests/MessageUtils.h
new file mode 100644
index 0000000000..3def8cd41b
--- /dev/null
+++ b/qpid/cpp/src/tests/MessageUtils.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.
+ *
+ */
+
+#include "qpid/broker/Message.h"
+#include "qpid/broker/MessageDelivery.h"
+#include "qpid/framing/AMQFrame.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 string& messageId, uint64_t contentSize = 0)
+ {
+ boost::intrusive_ptr<Message> msg(new Message());
+
+ AMQFrame method(in_place<MessageTransferBody>(ProtocolVersion(), 0, 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/qpid/cpp/src/tests/MockConnectionInputHandler.h b/qpid/cpp/src/tests/MockConnectionInputHandler.h
new file mode 100644
index 0000000000..89b6155355
--- /dev/null
+++ b/qpid/cpp/src/tests/MockConnectionInputHandler.h
@@ -0,0 +1,100 @@
+#ifndef _tests_MockConnectionInputHandler_h
+#define _tests_MockConnectionInputHandler_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/ConnectionInputHandler.h"
+#include "qpid/sys/ConnectionInputHandlerFactory.h"
+#include "qpid/sys/Monitor.h"
+
+struct MockConnectionInputHandler : public qpid::sys::ConnectionInputHandler {
+
+ MockConnectionInputHandler() : state(START) {}
+
+ ~MockConnectionInputHandler() {}
+
+ void received(qpid::framing::AMQFrame* framep) {
+ qpid::sys::Monitor::ScopedLock l(monitor);
+ frame = *framep;
+ setState(GOT_FRAME);
+ }
+
+ qpid::framing::AMQFrame waitForFrame() {
+ waitFor(GOT_FRAME);
+ return frame;
+ }
+
+ void waitForClosed() {
+ waitFor(CLOSED);
+ }
+
+ void closed() {
+ qpid::sys::Monitor::ScopedLock l(monitor);
+ setState(CLOSED);
+ }
+
+ void idleOut() {}
+ void idleIn() {}
+
+ private:
+ typedef enum { START, GOT_FRAME, CLOSED } State;
+
+ void setState(State s) {
+ state = s;
+ monitor.notify();
+ }
+
+ void waitFor(State s) {
+ qpid::sys::Monitor::ScopedLock l(monitor);
+ qpid::sys::Time deadline = qpid::sys::now() + 10*qpid::sys::TIME_SEC;
+ while (state != s)
+ CPPUNIT_ASSERT(monitor.wait(deadline));
+ }
+
+ qpid::sys::Monitor monitor;
+ State state;
+ qpid::framing::AMQFrame frame;
+};
+
+
+struct MockConnectionInputHandlerFactory : public qpid::sys::ConnectionInputHandlerFactory {
+ MockConnectionInputHandlerFactory() : handler(0) {}
+
+ qpid::sys::ConnectionInputHandler* create(qpid::sys::ConnectionOutputHandler*) {
+ qpid::sys::Monitor::ScopedLock lock(monitor);
+ handler = new MockConnectionInputHandler();
+ monitor.notifyAll();
+ return handler;
+ }
+
+ void waitForHandler() {
+ qpid::sys::Monitor::ScopedLock lock(monitor);
+ qpid::sys::Time deadline =
+ qpid::sys::now() + 500 * qpid::sys::TIME_SEC;
+ while (handler == 0)
+ CPPUNIT_ASSERT(monitor.wait(deadline));
+ }
+
+ MockConnectionInputHandler* handler;
+ qpid::sys::Monitor monitor;
+};
+
+
+
+#endif /*!_tests_MockConnectionInputHandler_h*/
diff --git a/qpid/cpp/src/tests/PollerTest.cpp b/qpid/cpp/src/tests/PollerTest.cpp
new file mode 100644
index 0000000000..fcb1d0dadf
--- /dev/null
+++ b/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/qpid/cpp/src/tests/QueuePolicyTest.cpp b/qpid/cpp/src/tests/QueuePolicyTest.cpp
new file mode 100644
index 0000000000..467f43638f
--- /dev/null
+++ b/qpid/cpp/src/tests/QueuePolicyTest.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 "qpid/broker/QueuePolicy.h"
+#include "qpid_test_plugin.h"
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+class QueuePolicyTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(QueuePolicyTest);
+ CPPUNIT_TEST(testCount);
+ CPPUNIT_TEST(testSize);
+ CPPUNIT_TEST(testBoth);
+ CPPUNIT_TEST(testSettings);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ void testCount(){
+ QueuePolicy policy(5, 0);
+ CPPUNIT_ASSERT(!policy.limitExceeded());
+ for (int i = 0; i < 5; i++) policy.enqueued(10);
+ CPPUNIT_ASSERT_EQUAL((uint64_t) 0, policy.getMaxSize());
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 5, policy.getMaxCount());
+ CPPUNIT_ASSERT(!policy.limitExceeded());
+ policy.enqueued(10);
+ CPPUNIT_ASSERT(policy.limitExceeded());
+ policy.dequeued(10);
+ CPPUNIT_ASSERT(!policy.limitExceeded());
+ policy.enqueued(10);
+ CPPUNIT_ASSERT(policy.limitExceeded());
+ }
+
+ void testSize(){
+ QueuePolicy policy(0, 50);
+ for (int i = 0; i < 5; i++) policy.enqueued(10);
+ CPPUNIT_ASSERT(!policy.limitExceeded());
+ policy.enqueued(10);
+ CPPUNIT_ASSERT(policy.limitExceeded());
+ policy.dequeued(10);
+ CPPUNIT_ASSERT(!policy.limitExceeded());
+ policy.enqueued(10);
+ CPPUNIT_ASSERT(policy.limitExceeded());
+ }
+
+ void testBoth(){
+ QueuePolicy policy(5, 50);
+ for (int i = 0; i < 5; i++) policy.enqueued(11);
+ CPPUNIT_ASSERT(policy.limitExceeded());
+ policy.dequeued(20);
+ CPPUNIT_ASSERT(!policy.limitExceeded());//fails
+ policy.enqueued(5);
+ policy.enqueued(10);
+ CPPUNIT_ASSERT(policy.limitExceeded());
+ }
+
+ void testSettings(){
+ //test reading and writing the policy from/to field table
+ FieldTable settings;
+ QueuePolicy a(101, 303);
+ a.update(settings);
+ QueuePolicy b(settings);
+ CPPUNIT_ASSERT_EQUAL(a.getMaxCount(), b.getMaxCount());
+ CPPUNIT_ASSERT_EQUAL(a.getMaxSize(), b.getMaxSize());
+ }
+};
+
+// Make this test suite a plugin.
+CPPUNIT_PLUGIN_IMPLEMENT();
+CPPUNIT_TEST_SUITE_REGISTRATION(QueuePolicyTest);
+
diff --git a/qpid/cpp/src/tests/QueueRegistryTest.cpp b/qpid/cpp/src/tests/QueueRegistryTest.cpp
new file mode 100644
index 0000000000..5fd861d6be
--- /dev/null
+++ b/qpid/cpp/src/tests/QueueRegistryTest.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 "qpid/broker/QueueRegistry.h"
+#include "qpid_test_plugin.h"
+#include <string>
+
+using namespace qpid::broker;
+
+class QueueRegistryTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(QueueRegistryTest);
+ CPPUNIT_TEST(testDeclare);
+ CPPUNIT_TEST(testDeclareTmp);
+ CPPUNIT_TEST(testFind);
+ CPPUNIT_TEST(testDestroy);
+ CPPUNIT_TEST_SUITE_END();
+
+ private:
+ std::string foo, bar;
+ QueueRegistry reg;
+ std::pair<Queue::shared_ptr, bool> qc;
+
+ public:
+ void setUp() {
+ foo = "foo";
+ bar = "bar";
+ }
+
+ void testDeclare() {
+ qc = reg.declare(foo, false, 0, 0);
+ Queue::shared_ptr q = qc.first;
+ CPPUNIT_ASSERT(q);
+ CPPUNIT_ASSERT(qc.second); // New queue
+ CPPUNIT_ASSERT_EQUAL(foo, q->getName());
+
+ qc = reg.declare(foo, false, 0, 0);
+ CPPUNIT_ASSERT_EQUAL(q, qc.first);
+ CPPUNIT_ASSERT(!qc.second);
+
+ qc = reg.declare(bar, false, 0, 0);
+ q = qc.first;
+ CPPUNIT_ASSERT(q);
+ CPPUNIT_ASSERT_EQUAL(true, qc.second);
+ CPPUNIT_ASSERT_EQUAL(bar, q->getName());
+ }
+
+ void testDeclareTmp()
+ {
+ qc = reg.declare(std::string(), false, 0, 0);
+ CPPUNIT_ASSERT(qc.second);
+ CPPUNIT_ASSERT_EQUAL(std::string("tmp_1"), qc.first->getName());
+ }
+
+ void testFind() {
+ CPPUNIT_ASSERT(reg.find(foo) == 0);
+
+ reg.declare(foo, false, 0, 0);
+ reg.declare(bar, false, 0, 0);
+ Queue::shared_ptr q = reg.find(bar);
+ CPPUNIT_ASSERT(q);
+ CPPUNIT_ASSERT_EQUAL(bar, q->getName());
+ }
+
+ void testDestroy() {
+ qc = reg.declare(foo, false, 0, 0);
+ reg.destroy(foo);
+ // Queue is gone from the registry.
+ CPPUNIT_ASSERT(reg.find(foo) == 0);
+ // Queue is not actually destroyed till we drop our reference.
+ CPPUNIT_ASSERT_EQUAL(foo, qc.first->getName());
+ // We shoud be the only reference.
+ CPPUNIT_ASSERT_EQUAL(1L, qc.first.use_count());
+ }
+};
+
+// Make this test suite a plugin.
+CPPUNIT_PLUGIN_IMPLEMENT();
+CPPUNIT_TEST_SUITE_REGISTRATION(QueueRegistryTest);
diff --git a/qpid/cpp/src/tests/QueueTest.cpp b/qpid/cpp/src/tests/QueueTest.cpp
new file mode 100644
index 0000000000..70132bce76
--- /dev/null
+++ b/qpid/cpp/src/tests/QueueTest.cpp
@@ -0,0 +1,258 @@
+ /*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/Queue.h"
+#include "qpid/broker/Deliverable.h"
+#include "qpid/broker/ExchangeRegistry.h"
+#include "qpid/broker/QueueRegistry.h"
+#include "qpid_test_plugin.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(): received(false) {};
+
+ virtual bool deliver(QueuedMessage& msg){
+ last = msg.payload;
+ received = true;
+ return true;
+ };
+ void notify() {}
+};
+
+class FailOnDeliver : public Deliverable
+{
+public:
+ void deliverTo(Queue::shared_ptr& queue)
+ {
+ throw Exception(QPID_MSG("Invalid delivery to " << queue->getName()));
+ }
+};
+
+class QueueTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(QueueTest);
+ CPPUNIT_TEST(testConsumers);
+ CPPUNIT_TEST(testRegistry);
+ CPPUNIT_TEST(testDequeue);
+ CPPUNIT_TEST(testBound);
+ CPPUNIT_TEST(testAsyncMessage);
+ CPPUNIT_TEST(testAsyncMessageCount);
+ CPPUNIT_TEST_SUITE_END();
+
+
+ public:
+ intrusive_ptr<Message> message(std::string exchange, std::string routingKey) {
+ intrusive_ptr<Message> msg(new Message());
+ AMQFrame method(in_place<MessageTransferBody>(
+ ProtocolVersion(), 0, 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;
+ }
+
+
+ void testAsyncMessage(){
+
+ Queue::shared_ptr queue(new Queue("my_test_queue", true));
+ intrusive_ptr<Message> received;
+
+ TestConsumer c1;
+ queue->consume(c1);
+
+
+ //Test basic delivery:
+ intrusive_ptr<Message> msg1 = message("e", "A");
+ msg1->enqueueAsync();//this is done on enqueue which is not called from process
+ queue->process(msg1);
+ sleep(2);
+
+ CPPUNIT_ASSERT(!c1.received);
+ msg1->enqueueComplete();
+
+ received = queue->dequeue().payload;
+ CPPUNIT_ASSERT_EQUAL(msg1.get(), received.get());
+
+
+ }
+
+
+ void testAsyncMessageCount(){
+ Queue::shared_ptr queue(new Queue("my_test_queue", true));
+ intrusive_ptr<Message> msg1 = 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;
+ CPPUNIT_ASSERT_EQUAL(compval, queue->getMessageCount());
+ msg1->enqueueComplete();
+ compval=1;
+ CPPUNIT_ASSERT_EQUAL(compval, queue->getMessageCount());
+
+ }
+
+ void testConsumers(){
+ Queue::shared_ptr queue(new Queue("my_queue", true));
+
+ //Test adding consumers:
+ TestConsumer c1;
+ TestConsumer c2;
+ queue->consume(c1);
+ queue->consume(c2);
+
+ CPPUNIT_ASSERT_EQUAL(uint32_t(2), queue->getConsumerCount());
+
+ //Test basic delivery:
+ intrusive_ptr<Message> msg1 = message("e", "A");
+ intrusive_ptr<Message> msg2 = message("e", "B");
+ intrusive_ptr<Message> msg3 = message("e", "C");
+
+ queue->deliver(msg1);
+ CPPUNIT_ASSERT(queue->dispatch(c1));
+ CPPUNIT_ASSERT_EQUAL(msg1.get(), c1.last.get());
+
+ queue->deliver(msg2);
+ CPPUNIT_ASSERT(queue->dispatch(c2));
+ CPPUNIT_ASSERT_EQUAL(msg2.get(), c2.last.get());
+
+ c1.received = false;
+ queue->deliver(msg3);
+ CPPUNIT_ASSERT(queue->dispatch(c1));
+ CPPUNIT_ASSERT_EQUAL(msg3.get(), c1.last.get());
+
+ //Test cancellation:
+ queue->cancel(c1);
+ CPPUNIT_ASSERT_EQUAL(uint32_t(1), queue->getConsumerCount());
+ queue->cancel(c2);
+ CPPUNIT_ASSERT_EQUAL(uint32_t(0), queue->getConsumerCount());
+ }
+
+ void testRegistry(){
+ //Test use of queues in registry:
+ QueueRegistry registry;
+ registry.declare("queue1", true, true);
+ registry.declare("queue2", true, true);
+ registry.declare("queue3", true, true);
+
+ CPPUNIT_ASSERT(registry.find("queue1"));
+ CPPUNIT_ASSERT(registry.find("queue2"));
+ CPPUNIT_ASSERT(registry.find("queue3"));
+
+ registry.destroy("queue1");
+ registry.destroy("queue2");
+ registry.destroy("queue3");
+
+ CPPUNIT_ASSERT(!registry.find("queue1"));
+ CPPUNIT_ASSERT(!registry.find("queue2"));
+ CPPUNIT_ASSERT(!registry.find("queue3"));
+ }
+
+ void testDequeue(){
+ Queue::shared_ptr queue(new Queue("my_queue", true));
+ intrusive_ptr<Message> msg1 = message("e", "A");
+ intrusive_ptr<Message> msg2 = message("e", "B");
+ intrusive_ptr<Message> msg3 = message("e", "C");
+ intrusive_ptr<Message> received;
+
+ queue->deliver(msg1);
+ queue->deliver(msg2);
+ queue->deliver(msg3);
+
+ CPPUNIT_ASSERT_EQUAL(uint32_t(3), queue->getMessageCount());
+
+ received = queue->dequeue().payload;
+ CPPUNIT_ASSERT_EQUAL(msg1.get(), received.get());
+ CPPUNIT_ASSERT_EQUAL(uint32_t(2), queue->getMessageCount());
+
+ received = queue->dequeue().payload;
+ CPPUNIT_ASSERT_EQUAL(msg2.get(), received.get());
+ CPPUNIT_ASSERT_EQUAL(uint32_t(1), queue->getMessageCount());
+
+ TestConsumer consumer;
+ queue->consume(consumer);
+ queue->dispatch(consumer);
+ if (!consumer.received)
+ sleep(2);
+
+ CPPUNIT_ASSERT_EQUAL(msg3.get(), consumer.last.get());
+ CPPUNIT_ASSERT_EQUAL(uint32_t(0), queue->getMessageCount());
+
+ received = queue->dequeue().payload;
+ CPPUNIT_ASSERT(!received);
+ CPPUNIT_ASSERT_EQUAL(uint32_t(0), queue->getMessageCount());
+
+ }
+
+ void 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);
+ }
+};
+
+// Make this test suite a plugin.
+CPPUNIT_PLUGIN_IMPLEMENT();
+CPPUNIT_TEST_SUITE_REGISTRATION(QueueTest);
+
+
diff --git a/qpid/cpp/src/tests/README b/qpid/cpp/src/tests/README
new file mode 100644
index 0000000000..3cf6fab2ad
--- /dev/null
+++ b/qpid/cpp/src/tests/README
@@ -0,0 +1,71 @@
+= 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 shared libraries containing CppUnit test plug-ins, run by
+the CppUnit DllPlugInTester program.
+
+run-unit-tests runs tests under valgrind, you can run it directly.
+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
+
+You can also Build and run selected tests via make:
+make check TESTS=run-unit-tests UNIT_TESTS=ClientChannelTest
+
+NOTE: If you use DllPlugInTester directly note that if foobar.so is in
+the current directory then this will fail with "can't load plugin":
+ # DllPluginTester foobar.so
+
+Instead you need to say:
+ # DllPluginTester ./foobar.so
+
+DllPluginTester uses dlopen() which only searches for shlibs
+in the standard places unless the filename contains a "/". In that
+case it just tries to open the filename.
+
+== 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/qpid/cpp/src/tests/RefCounted.cpp b/qpid/cpp/src/tests/RefCounted.cpp
new file mode 100644
index 0000000000..cd08a4491a
--- /dev/null
+++ b/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;
+
+BOOST_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/qpid/cpp/src/tests/SequenceNumberTest.cpp b/qpid/cpp/src/tests/SequenceNumberTest.cpp
new file mode 100644
index 0000000000..d227b78323
--- /dev/null
+++ b/qpid/cpp/src/tests/SequenceNumberTest.cpp
@@ -0,0 +1,220 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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_test_plugin.h"
+#include <iostream>
+#include "qpid/framing/SequenceNumber.h"
+#include "qpid/framing/SequenceNumberSet.h"
+
+using namespace qpid::framing;
+
+class SequenceNumberTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(SequenceNumberTest);
+ CPPUNIT_TEST(testIncrementPostfix);
+ CPPUNIT_TEST(testIncrementPrefix);
+ CPPUNIT_TEST(testWrapAround);
+ CPPUNIT_TEST(testCondense);
+ CPPUNIT_TEST(testCondenseSingleRange);
+ CPPUNIT_TEST(testCondenseSingleItem);
+ CPPUNIT_TEST(testDifference);
+ CPPUNIT_TEST(testDifferenceWithWrapAround1);
+ CPPUNIT_TEST(testDifferenceWithWrapAround2);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+
+ void testIncrementPostfix()
+ {
+ SequenceNumber a;
+ SequenceNumber b;
+ CPPUNIT_ASSERT(!(a > b));
+ CPPUNIT_ASSERT(!(b < a));
+ CPPUNIT_ASSERT(a == b);
+
+ SequenceNumber c = a++;
+ CPPUNIT_ASSERT(a > b);
+ CPPUNIT_ASSERT(b < a);
+ CPPUNIT_ASSERT(a != b);
+ CPPUNIT_ASSERT(c < a);
+ CPPUNIT_ASSERT(a != c);
+
+ b++;
+ CPPUNIT_ASSERT(!(a > b));
+ CPPUNIT_ASSERT(!(b < a));
+ CPPUNIT_ASSERT(a == b);
+ CPPUNIT_ASSERT(c < b);
+ CPPUNIT_ASSERT(b != c);
+ }
+
+ void testIncrementPrefix()
+ {
+ SequenceNumber a;
+ SequenceNumber b;
+ CPPUNIT_ASSERT(!(a > b));
+ CPPUNIT_ASSERT(!(b < a));
+ CPPUNIT_ASSERT(a == b);
+
+ SequenceNumber c = ++a;
+ CPPUNIT_ASSERT(a > b);
+ CPPUNIT_ASSERT(b < a);
+ CPPUNIT_ASSERT(a != b);
+ CPPUNIT_ASSERT(a == c);
+
+ ++b;
+ CPPUNIT_ASSERT(!(a > b));
+ CPPUNIT_ASSERT(!(b < a));
+ CPPUNIT_ASSERT(a == b);
+ }
+
+ void 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);
+ }
+
+ void checkComparison(SequenceNumber& a, SequenceNumber& b, int gap)
+ {
+ //increment until b wraps around
+ for (int i = 0; i < (gap + 2); i++) {
+ CPPUNIT_ASSERT(++a < ++b);//test prefix
+ }
+ //keep incrementing until a also wraps around
+ for (int i = 0; i < (gap + 2); i++) {
+ CPPUNIT_ASSERT(a++ < b++);//test postfix
+ }
+ //let a 'catch up'
+ for (int i = 0; i < gap; i++) {
+ a++;
+ }
+ CPPUNIT_ASSERT(a == b);
+ CPPUNIT_ASSERT(++a > b);
+ }
+
+ void 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));
+ CPPUNIT_ASSERT_EQUAL(expected, actual);
+ }
+
+ void 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));
+ CPPUNIT_ASSERT_EQUAL(expected, actual);
+ }
+
+ void testCondenseSingleItem()
+ {
+ SequenceNumberSet set;
+ set.push_back(SequenceNumber(1));
+ SequenceNumberSet actual = set.condense();
+
+ SequenceNumberSet expected;
+ expected.addRange(SequenceNumber(1), SequenceNumber(1));
+ CPPUNIT_ASSERT_EQUAL(expected, actual);
+ }
+
+ void testDifference()
+ {
+ SequenceNumber a;
+ SequenceNumber b;
+
+ for (int i = 0; i < 10; i++, ++a) {
+ CPPUNIT_ASSERT_EQUAL(i, a - b);
+ CPPUNIT_ASSERT_EQUAL(-i, b - a);
+ }
+
+ b = a;
+
+ for (int i = 0; i < 10; i++, ++b) {
+ CPPUNIT_ASSERT_EQUAL(-i, a - b);
+ CPPUNIT_ASSERT_EQUAL(i, b - a);
+ }
+ }
+
+ void testDifferenceWithWrapAround1()
+ {
+ const uint32_t max = 0xFFFFFFFF;
+ SequenceNumber a(max - 5);
+ SequenceNumber b(max - 10);
+ checkDifference(a, b, 5);
+ }
+
+ void testDifferenceWithWrapAround2()
+ {
+ const uint32_t max_signed = 0x7FFFFFFF;
+ SequenceNumber c(max_signed - 5);
+ SequenceNumber d(max_signed - 10);
+ checkDifference(c, d, 5);
+ }
+
+ void checkDifference(SequenceNumber& a, SequenceNumber& b, int gap)
+ {
+ CPPUNIT_ASSERT_EQUAL(gap, a - b);
+ CPPUNIT_ASSERT_EQUAL(-gap, b - a);
+
+ //increment until b wraps around
+ for (int i = 0; i < (gap + 2); i++, ++a, ++b) {
+ CPPUNIT_ASSERT_EQUAL(gap, a - b);
+ }
+ //keep incrementing until a also wraps around
+ for (int i = 0; i < (gap + 2); i++, ++a, ++b) {
+ CPPUNIT_ASSERT_EQUAL(gap, a - b);
+ }
+ //let b catch up and overtake
+ for (int i = 0; i < (gap*2); i++, ++b) {
+ CPPUNIT_ASSERT_EQUAL(gap - i, a - b);
+ CPPUNIT_ASSERT_EQUAL(i - gap, b - a);
+ }
+ }
+};
+
+// Make this test suite a plugin.
+CPPUNIT_PLUGIN_IMPLEMENT();
+CPPUNIT_TEST_SUITE_REGISTRATION(SequenceNumberTest);
diff --git a/qpid/cpp/src/tests/SequenceSet.cpp b/qpid/cpp/src/tests/SequenceSet.cpp
new file mode 100644
index 0000000000..c98b02b4b7
--- /dev/null
+++ b/qpid/cpp/src/tests/SequenceSet.cpp
@@ -0,0 +1,139 @@
+/*
+ *
+ * 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"
+
+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());
+ }
+};
+
+BOOST_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(t.contains(i));
+
+ RangeExpectations().expect(2, 10).check(t);
+}
+
+BOOST_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);
+}
+
+BOOST_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/qpid/cpp/src/tests/Serializer.cpp b/qpid/cpp/src/tests/Serializer.cpp
new file mode 100644
index 0000000000..51b739218d
--- /dev/null
+++ b/qpid/cpp/src/tests/Serializer.cpp
@@ -0,0 +1,157 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/Runnable.h"
+#include "qpid/sys/Thread.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Serializer.h"
+
+#include <boost/bind.hpp>
+#include <boost/utility/value_init.hpp>
+#include "unit_test.h"
+
+#include <set>
+
+#include <unistd.h>
+
+QPID_AUTO_TEST_SUITE(SerializerTestSuite)
+
+
+using namespace qpid;
+using namespace qpid::sys;
+using namespace qpid::framing;
+using namespace std;
+
+typedef Serializer<boost::function<void()> > BoostFunctionSerializer;
+
+/** Test for concurrent calls */
+struct Tester {
+ Monitor lock;
+ size_t count;
+ size_t collisions;
+ set<long> threads;
+
+ Tester() : count(0), collisions(0) {}
+
+ void test() {
+ if (lock.trylock()) { // Check for concurrent calls.
+ ++count;
+ threads.insert(Thread::logId()); // Record thread.
+ usleep(1000); // Encourage overlap.
+ lock.notify();
+ lock.unlock();
+ }
+ else
+ ++collisions;
+ }
+};
+
+void execute(BoostFunctionSerializer& s, boost::function<void()> t)
+{
+ s.execute(t);
+}
+
+BOOST_AUTO_TEST_CASE(testSingleThread) {
+ // Verify that we call in the same thread by default.
+ Tester tester;
+ BoostFunctionSerializer s;
+ for (int i = 0; i < 100; ++i)
+ execute(s, boost::bind(&Tester::test, &tester));
+ // All should be executed in this thread.
+ BOOST_CHECK_EQUAL(0u, tester.collisions);
+ BOOST_CHECK_EQUAL(100u, tester.count);
+ BOOST_REQUIRE_EQUAL(1u, tester.threads.size());
+ BOOST_CHECK_EQUAL(Thread::logId(), *tester.threads.begin());
+}
+
+
+BOOST_AUTO_TEST_CASE(testSingleThreadNoImmediate) {
+ // Verify that we call in different thread if immediate=false.
+ Tester tester;
+ BoostFunctionSerializer s(false);
+ for (int i = 0; i < 100; ++i)
+ execute(s, boost::bind(&Tester::test, &tester));
+ {
+ // Wait for dispatch thread to complete.
+ Mutex::ScopedLock l(tester.lock);
+ while (tester.count != 100)
+ tester.lock.wait();
+ }
+ BOOST_CHECK_EQUAL(0u, tester.collisions);
+ BOOST_CHECK_EQUAL(100u, tester.count);
+ BOOST_REQUIRE_EQUAL(1u, tester.threads.size());
+ BOOST_CHECK(Thread::logId() != *tester.threads.begin());
+}
+
+struct Caller : public Runnable, public Tester {
+ Caller(BoostFunctionSerializer& s) : serializer(s) {}
+ void run() { execute(serializer, boost::bind(&Tester::test, this)); }
+ BoostFunctionSerializer& serializer;
+};
+
+BOOST_AUTO_TEST_CASE(testDispatchThread) {
+ BoostFunctionSerializer s;
+ Caller caller(s);
+ Thread threads[100];
+ // Concurrent calls.
+ for (size_t i = 0; i < 100; ++i)
+ threads[i] = Thread(caller);
+ for (size_t i = 0; i < 100; ++i)
+ threads[i].join();
+
+ // At least one task should have been queued.
+ BOOST_CHECK_EQUAL(0u, caller.collisions);
+ BOOST_CHECK(caller.threads.size() > 2u);
+ BOOST_CHECK(caller.threads.size() < 100u);
+}
+
+
+std::auto_ptr<BoostFunctionSerializer> serializer;
+
+struct CallDispatch : public Runnable {
+ void run() {
+ serializer->dispatch();
+ }
+};
+
+void notifyDispatch() {
+ static CallDispatch cd;
+ Thread t(cd);
+}
+
+// Use externally created threads.
+BOOST_AUTO_TEST_CASE(testExternalDispatch) {
+ serializer.reset(new BoostFunctionSerializer(false, &notifyDispatch));
+ Tester tester;
+ for (int i = 0; i < 100; ++i)
+ execute(*serializer, boost::bind(&Tester::test, &tester));
+ {
+ // Wait for dispatch thread to complete.
+ Mutex::ScopedLock l(tester.lock);
+ while (tester.count != 100)
+ tester.lock.wait();
+ }
+ BOOST_CHECK_EQUAL(0u, tester.collisions);
+ BOOST_CHECK_EQUAL(100u, tester.count);
+ BOOST_CHECK(Thread::logId() != *tester.threads.begin());
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/SessionState.cpp b/qpid/cpp/src/tests/SessionState.cpp
new file mode 100644
index 0000000000..56d0055ed8
--- /dev/null
+++ b/qpid/cpp/src/tests/SessionState.cpp
@@ -0,0 +1,146 @@
+/*
+ *
+ * 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/SessionState.h"
+#include "qpid/Exception.h"
+
+#include <boost/bind.hpp>
+#include "unit_test.h"
+
+QPID_AUTO_TEST_SUITE(SessionStateTestSuite)
+
+using namespace std;
+using namespace qpid::framing;
+using namespace boost;
+
+// Create a frame with a one-char string.
+AMQFrame& frame(char s) {
+ static AMQFrame frame;
+ frame.setBody(AMQContentBody(string(&s, 1)));
+ return frame;
+}
+
+// Extract the one-char string from a frame.
+char charFromFrame(const AMQFrame& f) {
+ const AMQContentBody* b=dynamic_cast<const AMQContentBody*>(f.getBody());
+ BOOST_REQUIRE(b && b->getData().size() > 0);
+ return b->getData()[0];
+}
+
+// Sent chars as frames
+void sent(SessionState& session, const std::string& frames) {
+ for_each(frames.begin(), frames.end(),
+ bind(&SessionState::sent, ref(session), bind(frame, _1)));
+}
+
+// Received chars as frames
+void received(SessionState& session, const std::string& frames) {
+ for_each(frames.begin(), frames.end(),
+ bind(&SessionState::received, ref(session), bind(frame, _1)));
+}
+
+// Make a string from a ReplayRange.
+std::string replayChars(const SessionState::Replay& frames) {
+ string result(frames.size(), ' ');
+ transform(frames.begin(), frames.end(), result.begin(),
+ bind(&charFromFrame, _1));
+ return result;
+}
+
+namespace qpid {
+namespace framing {
+
+bool operator==(const AMQFrame& a, const AMQFrame& b) {
+ const AMQContentBody* ab=dynamic_cast<const AMQContentBody*>(a.getBody());
+ const AMQContentBody* bb=dynamic_cast<const AMQContentBody*>(b.getBody());
+ return ab && bb && ab->getData() == bb->getData();
+}
+
+}} // namespace qpid::framing
+
+
+BOOST_AUTO_TEST_CASE(testSent) {
+ // Test that we send solicit-ack at the right interval.
+ AMQContentBody f;
+ SessionState s1(1);
+ BOOST_CHECK(s1.sent(f));
+ BOOST_CHECK(s1.sent(f));
+ BOOST_CHECK(s1.sent(f));
+
+ SessionState s3(3);
+ BOOST_CHECK(!s3.sent(f));
+ BOOST_CHECK(!s3.sent(f));
+ BOOST_CHECK(s3.sent(f));
+
+ BOOST_CHECK(!s3.sent(f));
+ BOOST_CHECK(!s3.sent(f));
+ s3.receivedAck(4);
+ BOOST_CHECK(!s3.sent(f));
+ BOOST_CHECK(!s3.sent(f));
+ BOOST_CHECK(s3.sent(f));
+}
+
+BOOST_AUTO_TEST_CASE(testReplay) {
+ // Replay of all frames.
+ SessionState session(100);
+ sent(session, "abc");
+ session.suspend(); session.resuming();
+ session.receivedAck(-1);
+ BOOST_CHECK_EQUAL(replayChars(session.replay()), "abc");
+
+ // Replay with acks
+ session.receivedAck(0); // ack a.
+ session.suspend();
+ session.resuming();
+ session.receivedAck(1); // ack b.
+ BOOST_CHECK_EQUAL(replayChars(session.replay()), "c");
+
+ // Replay after further frames.
+ sent(session, "def");
+ session.suspend();
+ session.resuming();
+ session.receivedAck(3);
+ BOOST_CHECK_EQUAL(replayChars(session.replay()), "ef");
+
+ // Bad ack, too high
+ try {
+ session.receivedAck(6);
+ BOOST_FAIL("expected exception");
+ } catch(const std::exception&) {}
+
+}
+
+BOOST_AUTO_TEST_CASE(testReceived) {
+ // Check that we request acks at the right interval.
+ AMQContentBody f;
+ SessionState s1(1);
+ BOOST_CHECK_EQUAL(0u, *s1.received(f));
+ BOOST_CHECK_EQUAL(1u, *s1.received(f));
+ BOOST_CHECK_EQUAL(2u, *s1.received(f));
+
+ SessionState s3(3);
+ BOOST_CHECK(!s3.received(f));
+ BOOST_CHECK(!s3.received(f));
+ BOOST_CHECK_EQUAL(2u, *s3.received(f));
+
+ BOOST_CHECK(!s3.received(f));
+ BOOST_CHECK(!s3.received(f));
+ BOOST_CHECK_EQUAL(5u, *s3.received(f));
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/Shlib.cpp b/qpid/cpp/src/tests/Shlib.cpp
new file mode 100644
index 0000000000..3adc33aac9
--- /dev/null
+++ b/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*);
+
+BOOST_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&) {}
+}
+
+BOOST_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/qpid/cpp/src/tests/SimpleTestCaseBase.cpp b/qpid/cpp/src/tests/SimpleTestCaseBase.cpp
new file mode 100644
index 0000000000..4f071cd02b
--- /dev/null
+++ b/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(TestOptions& 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(TestOptions& options, const int _messages) :
+ connection(options.trace), 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/qpid/cpp/src/tests/SimpleTestCaseBase.h b/qpid/cpp/src/tests/SimpleTestCaseBase.h
new file mode 100644
index 0000000000..7f94fa7e1c
--- /dev/null
+++ b/qpid/cpp/src/tests/SimpleTestCaseBase.h
@@ -0,0 +1,88 @@
+#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 "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(TestOptions& 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(TestOptions& 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, TestOptions& options) = 0;
+
+ virtual ~SimpleTestCaseBase() {}
+
+ void start();
+ void stop();
+ void report(client::Message& report);
+};
+
+}
+
+#endif
diff --git a/qpid/cpp/src/tests/SocketProxy.h b/qpid/cpp/src/tests/SocketProxy.h
new file mode 100644
index 0000000000..a37c1f2c3e
--- /dev/null
+++ b/qpid/cpp/src/tests/SocketProxy.h
@@ -0,0 +1,164 @@
+#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/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())
+ {
+ int r=::pipe(closePipe);
+ if (r<0) throwErrno(QPID_MSG("::pipe returned " << r));
+ 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;
+ }
+ write(closePipe[1], this, 1); // Random byte to closePipe
+ thread.join();
+ client.close();
+ ::close(closePipe[0]);
+ ::close(closePipe[1]);
+ }
+
+ 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::strError(errno));
+ }
+ static void throwIf(bool condition, const std::string& msg) {
+ if (condition) throw qpid::Exception(msg);
+ }
+
+ struct FdSet : fd_set {
+ FdSet() : maxFd(0) { clear(); }
+ void clear() { FD_ZERO(this); }
+ void set(int fd) { FD_SET(fd, this); maxFd = std::max(maxFd, fd); }
+ bool isSet(int fd) const { return FD_ISSET(fd, this); }
+ bool operator[](int fd) const { return isSet(fd); }
+
+ int maxFd;
+ };
+
+ enum { RD=1, WR=2, ER=4 };
+
+ struct Selector {
+ FdSet rd, wr, er;
+
+ void set(int fd, int sets) {
+ if (sets & RD) rd.set(fd);
+ if (sets & WR) wr.set(fd);
+ if (sets & ER) er.set(fd);
+ }
+
+ int select() {
+ for (;;) {
+ int maxFd = std::max(rd.maxFd, std::max(wr.maxFd, er.maxFd));
+ int r = ::select(maxFd + 1, &rd, &wr, &er, NULL);
+ if (r == -1 && errno == EINTR) continue;
+ if (r < 0) throwErrno(QPID_MSG("select returned " <<r));
+ return r;
+ }
+ }
+ };
+
+ void run() {
+ std::auto_ptr<qpid::sys::Socket> server;
+ try {
+ // Accept incoming connections, watch closePipe.
+ Selector accept;
+ accept.set(listener.toFd(), RD|ER);
+ accept.set(closePipe[0], RD|ER);
+ accept.select();
+ throwIf(accept.rd[closePipe[0]], "Closed by close()");
+ throwIf(!accept.rd[listener.toFd()],"Accept failed");
+ server.reset(listener.accept(0, 0));
+
+ // Pump data between client & server sockets, watch closePipe.
+ char buffer[1024];
+ for (;;) {
+ Selector select;
+ select.set(server->toFd(), RD|ER);
+ select.set(client.toFd(), RD|ER);
+ select.set(closePipe[0], RD|ER);
+ select.select();
+ throwIf(select.rd[closePipe[0]], "Closed by close()");
+ // Read even if fd is in error to throw a useful exception.
+ bool gotData=false;
+ if (select.rd[server->toFd()] || select.er[server->toFd()]) {
+ client.write(buffer, server->read(buffer, sizeof(buffer)));
+ gotData=true;
+ }
+ if (select.rd[client.toFd()] || select.er[client.toFd()]) {
+ server->write(buffer, client.read(buffer, sizeof(buffer)));
+ gotData=true;
+ }
+ throwIf(!gotData, "No data from select()");
+ }
+ }
+ catch (const std::exception& e) {
+ QPID_LOG(debug, "SocketProxy::run exiting: " << e.what());
+ }
+ if (server.get()) server->close();
+ close();
+ }
+
+ mutable qpid::sys::Mutex lock;
+ bool closed;
+ qpid::sys::Socket client, listener;
+ uint16_t port;
+ int closePipe[2];
+ qpid::sys::Thread thread;
+};
+
+#endif
diff --git a/qpid/cpp/src/tests/TestCase.h b/qpid/cpp/src/tests/TestCase.h
new file mode 100644
index 0000000000..07bdd68933
--- /dev/null
+++ b/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 "qpid/client/Message.h"
+#include "TestOptions.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, TestOptions& 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/qpid/cpp/src/tests/TestOptions.h b/qpid/cpp/src/tests/TestOptions.h
new file mode 100644
index 0000000000..87710964d6
--- /dev/null
+++ b/qpid/cpp/src/tests/TestOptions.h
@@ -0,0 +1,94 @@
+#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 <iostream>
+#include <exception>
+
+namespace qpid {
+
+struct TestOptions : public qpid::Options
+{
+ TestOptions(const std::string& helpText_=std::string()) :
+ Options("Test Options"),
+ host("localhost"), port(TcpAddress::DEFAULT_PORT),
+ clientid("cpp"), username("guest"), password("guest"),
+ help(false), helpText(helpText_)
+ {
+ addOptions()
+ ("host,h", optValue(host, "HOST"), "Broker host to connect to")
+ // TODO aconway 2007-06-26: broker is synonym for host. Drop broker?
+ ("broker,b", optValue(host, "HOST"), "Broker host to connect to")
+ ("port,p", optValue(port, "PORT"), "Broker port to connect to")
+ ("virtualhost,v", optValue(virtualhost, "VHOST"), "virtual host")
+ ("clientname,n", optValue(clientid, "ID"), "unique client identifier")
+ ("username", optValue(username, "USER"), "user name for broker log in.")
+ ("password", optValue(password, "USER"), "password for broker log in.")
+ ("help", optValue(help), "print this usage statement");
+ 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());
+ }
+ trace = log.trace;
+ qpid::log::Logger::instance().configure(log, argv[0]);
+ 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(host, port, username, password, virtualhost);
+ }
+
+
+ std::string host;
+ uint16_t port;
+ std::string virtualhost;
+ std::string clientid;
+ std::string username;
+ std::string password;
+ bool trace;
+ bool help;
+ log::Options log;
+ std::string helpText;
+};
+
+}
+
+#endif
diff --git a/qpid/cpp/src/tests/TimerTest.cpp b/qpid/cpp/src/tests/TimerTest.cpp
new file mode 100644
index 0000000000..2693d4a787
--- /dev/null
+++ b/qpid/cpp/src/tests/TimerTest.cpp
@@ -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.
+ *
+ */
+#include "qpid/broker/Timer.h"
+#include "qpid/sys/Monitor.h"
+#include "qpid_test_plugin.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 TimerTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(TimerTest);
+ CPPUNIT_TEST(testGeneral);
+ CPPUNIT_TEST_SUITE_END();
+
+ 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);
+ CPPUNIT_ASSERT(fired);
+ CPPUNIT_ASSERT_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));
+ CPPUNIT_ASSERT_MESSAGE(msg, difference < tolerance);
+ }
+
+ void wait(Duration d)
+ {
+ Monitor::ScopedLock l(monitor);
+ monitor.wait(AbsTime(now(), d));
+ }
+ };
+
+ class DummyRunner : public Runnable
+ {
+ public:
+ void run() {}
+ };
+
+public:
+
+ void 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);
+ }
+};
+
+// Make this test suite a plugin.
+CPPUNIT_PLUGIN_IMPLEMENT();
+CPPUNIT_TEST_SUITE_REGISTRATION(TimerTest);
+
diff --git a/qpid/cpp/src/tests/TopicExchangeTest.cpp b/qpid/cpp/src/tests/TopicExchangeTest.cpp
new file mode 100644
index 0000000000..adb937179f
--- /dev/null
+++ b/qpid/cpp/src/tests/TopicExchangeTest.cpp
@@ -0,0 +1,200 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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 "qpid_test_plugin.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))
+
+// Allow CPPUNIT_EQUALS to print a Tokens.
+CppUnit::OStringStream& operator <<(CppUnit::OStringStream& out, const Tokens& v)
+{
+ out << "[ ";
+ for (Tokens::const_iterator i = v.begin();
+ i != v.end(); ++i)
+ {
+ out << '"' << *i << '"' << (i+1 == v.end() ? "]" : ", ");
+ }
+ return out;
+}
+
+
+class TokensTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(TokensTest);
+ CPPUNIT_TEST(testTokens);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ void testTokens()
+ {
+ Tokens tokens("hello.world");
+ const char* expect[] = {"hello", "world"};
+ CPPUNIT_ASSERT_EQUAL(TOKENS(expect), tokens);
+
+ tokens = "a.b.c";
+ const char* expect2[] = { "a", "b", "c" };
+ CPPUNIT_ASSERT_EQUAL(TOKENS(expect2), tokens);
+
+ tokens = "";
+ CPPUNIT_ASSERT(tokens.empty());
+
+ tokens = "x";
+ const char* expect3[] = { "x" };
+ CPPUNIT_ASSERT_EQUAL(TOKENS(expect3), tokens);
+
+ tokens = (".x");
+ const char* expect4[] = { "", "x" };
+ CPPUNIT_ASSERT_EQUAL(TOKENS(expect4), tokens);
+
+ tokens = ("x.");
+ const char* expect5[] = { "x", "" };
+ CPPUNIT_ASSERT_EQUAL(TOKENS(expect5), tokens);
+
+ tokens = (".");
+ const char* expect6[] = { "", "" };
+ CPPUNIT_ASSERT_EQUAL(TOKENS(expect6), tokens);
+
+ tokens = ("..");
+ const char* expect7[] = { "", "", "" };
+ CPPUNIT_ASSERT_EQUAL(TOKENS(expect7), tokens);
+ }
+
+};
+
+#define ASSERT_NORMALIZED(expect, pattern) \
+ CPPUNIT_ASSERT_EQUAL(Tokens(expect), static_cast<Tokens>(TopicPattern(pattern)))
+class TopicPatternTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(TopicPatternTest);
+ CPPUNIT_TEST(testNormalize);
+ CPPUNIT_TEST(testPlain);
+ CPPUNIT_TEST(testStar);
+ CPPUNIT_TEST(testHash);
+ CPPUNIT_TEST(testMixed);
+ CPPUNIT_TEST(testCombo);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+
+ void testNormalize()
+ {
+ CPPUNIT_ASSERT(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.*.#.*.#.*");
+ }
+
+ void testPlain() {
+ TopicPattern p("ab.cd.e");
+ CPPUNIT_ASSERT(p.match("ab.cd.e"));
+ CPPUNIT_ASSERT(!p.match("abx.cd.e"));
+ CPPUNIT_ASSERT(!p.match("ab.cd"));
+ CPPUNIT_ASSERT(!p.match("ab.cd..e."));
+ CPPUNIT_ASSERT(!p.match("ab.cd.e."));
+ CPPUNIT_ASSERT(!p.match(".ab.cd.e"));
+
+ p = "";
+ CPPUNIT_ASSERT(p.match(""));
+
+ p = ".";
+ CPPUNIT_ASSERT(p.match("."));
+ }
+
+
+ void testStar()
+ {
+ TopicPattern p("a.*.b");
+ CPPUNIT_ASSERT(p.match("a.xx.b"));
+ CPPUNIT_ASSERT(!p.match("a.b"));
+
+ p = "*.x";
+ CPPUNIT_ASSERT(p.match("y.x"));
+ CPPUNIT_ASSERT(p.match(".x"));
+ CPPUNIT_ASSERT(!p.match("x"));
+
+ p = "x.x.*";
+ CPPUNIT_ASSERT(p.match("x.x.y"));
+ CPPUNIT_ASSERT(p.match("x.x."));
+ CPPUNIT_ASSERT(!p.match("x.x"));
+ CPPUNIT_ASSERT(!p.match("q.x.y"));
+ }
+
+ void testHash()
+ {
+ TopicPattern p("a.#.b");
+ CPPUNIT_ASSERT(p.match("a.b"));
+ CPPUNIT_ASSERT(p.match("a.x.b"));
+ CPPUNIT_ASSERT(p.match("a..x.y.zz.b"));
+ CPPUNIT_ASSERT(!p.match("a.b."));
+ CPPUNIT_ASSERT(!p.match("q.x.b"));
+
+ p = "a.#";
+ CPPUNIT_ASSERT(p.match("a"));
+ CPPUNIT_ASSERT(p.match("a.b"));
+ CPPUNIT_ASSERT(p.match("a.b.c"));
+
+ p = "#.a";
+ CPPUNIT_ASSERT(p.match("a"));
+ CPPUNIT_ASSERT(p.match("x.y.a"));
+ }
+
+ void testMixed()
+ {
+ TopicPattern p("*.x.#.y");
+ CPPUNIT_ASSERT(p.match("a.x.y"));
+ CPPUNIT_ASSERT(p.match("a.x.p.qq.y"));
+ CPPUNIT_ASSERT(!p.match("a.a.x.y"));
+ CPPUNIT_ASSERT(!p.match("aa.x.b.c"));
+
+ p = "a.#.b.*";
+ CPPUNIT_ASSERT(p.match("a.b.x"));
+ CPPUNIT_ASSERT(p.match("a.x.x.x.b.x"));
+ }
+
+ void testCombo() {
+ TopicPattern p("*.#.#.*.*.#");
+ CPPUNIT_ASSERT(p.match("x.y.z"));
+ CPPUNIT_ASSERT(p.match("x.y.z.a.b.c"));
+ CPPUNIT_ASSERT(!p.match("x.y"));
+ CPPUNIT_ASSERT(!p.match("x"));
+ }
+};
+
+
+// Make this test suite a plugin.
+CPPUNIT_PLUGIN_IMPLEMENT();
+CPPUNIT_TEST_SUITE_REGISTRATION(TopicPatternTest);
+CPPUNIT_TEST_SUITE_REGISTRATION(TokensTest);
diff --git a/qpid/cpp/src/tests/TxAckTest.cpp b/qpid/cpp/src/tests/TxAckTest.cpp
new file mode 100644
index 0000000000..89b98cb93c
--- /dev/null
+++ b/qpid/cpp/src/tests/TxAckTest.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/broker/NullMessageStore.h"
+#include "qpid/broker/RecoveryManager.h"
+#include "qpid/broker/TxAck.h"
+#include "qpid_test_plugin.h"
+#include <iostream>
+#include <list>
+#include <vector>
+
+using std::list;
+using std::vector;
+using boost::intrusive_ptr;
+using namespace qpid;
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+class TxAckTest : public CppUnit::TestCase
+{
+
+ class TestMessageStore : public NullMessageStore
+ {
+ public:
+ vector<intrusive_ptr<PersistableMessage> > dequeued;
+
+ void dequeue(TransactionContext*, intrusive_ptr<PersistableMessage>& msg, const PersistableQueue& /*queue*/)
+ {
+ dequeued.push_back(msg);
+ }
+
+ TestMessageStore() : NullMessageStore() {}
+ ~TestMessageStore(){}
+ };
+
+ CPPUNIT_TEST_SUITE(TxAckTest);
+ CPPUNIT_TEST(testPrepare);
+ CPPUNIT_TEST(testCommit);
+ CPPUNIT_TEST_SUITE_END();
+
+
+ AccumulatedAck acked;
+ TestMessageStore store;
+ Queue::shared_ptr queue;
+ vector<intrusive_ptr<Message> > messages;
+ list<DeliveryRecord> deliveries;
+ TxAck op;
+
+
+public:
+
+ TxAckTest() : acked(0), queue(new Queue("my_queue", false, &store, 0)), op(acked, deliveries)
+ {
+ for(int i = 0; i < 10; i++){
+ intrusive_ptr<Message> msg(new Message());
+ AMQFrame method(in_place<MessageTransferBody>(
+ ProtocolVersion(), 0, "exchange", 0, 0));
+ AMQFrame header(in_place<AMQHeaderBody>());
+ msg->getFrames().append(method);
+ msg->getFrames().append(header);
+ msg->getProperties<DeliveryProperties>()->setDeliveryMode(PERSISTENT);
+ msg->getProperties<DeliveryProperties>()->setRoutingKey("routing_key");
+ messages.push_back(msg);
+ QueuedMessage qm(queue.get());
+ qm.payload = msg;
+ deliveries.push_back(DeliveryRecord(qm, queue, "xyz", DeliveryToken::shared_ptr(), (i+1), true));
+ }
+
+ //assume msgs 1-5, 7 and 9 are all acked (i.e. 6, 8 & 10 are not)
+ acked.mark = 5;
+ acked.update(7, 7);
+ acked.update(9, 9);
+ }
+
+ void testPrepare()
+ {
+ //ensure acked messages are discarded, i.e. dequeued from store
+ op.prepare(0);
+ CPPUNIT_ASSERT_EQUAL((size_t) 7, store.dequeued.size());
+ CPPUNIT_ASSERT_EQUAL((size_t) 10, deliveries.size());
+ int dequeued[] = {0, 1, 2, 3, 4, 6, 8};
+ for (int i = 0; i < 7; i++) {
+ CPPUNIT_ASSERT_EQUAL(static_pointer_cast<PersistableMessage>(messages[dequeued[i]]), store.dequeued[i]);
+ }
+ }
+
+ void testCommit()
+ {
+ //emsure acked messages are removed from list
+ op.commit();
+ CPPUNIT_ASSERT_EQUAL((size_t) 3, deliveries.size());
+ list<DeliveryRecord>::iterator i = deliveries.begin();
+ CPPUNIT_ASSERT(i->matches(6));//msg 6
+ CPPUNIT_ASSERT((++i)->matches(8));//msg 8
+ CPPUNIT_ASSERT((++i)->matches(10));//msg 10
+ }
+};
+
+// Make this test suite a plugin.
+CPPUNIT_PLUGIN_IMPLEMENT();
+CPPUNIT_TEST_SUITE_REGISTRATION(TxAckTest);
+
diff --git a/qpid/cpp/src/tests/TxBufferTest.cpp b/qpid/cpp/src/tests/TxBufferTest.cpp
new file mode 100644
index 0000000000..afe6d2b0fc
--- /dev/null
+++ b/qpid/cpp/src/tests/TxBufferTest.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 "qpid/broker/TxBuffer.h"
+#include "qpid_test_plugin.h"
+#include <iostream>
+#include <vector>
+#include "TxMocks.h"
+
+using namespace qpid::broker;
+using boost::static_pointer_cast;
+
+class TxBufferTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(TxBufferTest);
+ CPPUNIT_TEST(testCommitLocal);
+ CPPUNIT_TEST(testFailOnCommitLocal);
+ CPPUNIT_TEST(testPrepare);
+ CPPUNIT_TEST(testFailOnPrepare);
+ CPPUNIT_TEST(testRollback);
+ CPPUNIT_TEST(testBufferIsClearedAfterRollback);
+ CPPUNIT_TEST(testBufferIsClearedAfterCommit);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+
+ void 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));
+
+ CPPUNIT_ASSERT(buffer.commitLocal(&store));
+ store.check();
+ CPPUNIT_ASSERT(store.isCommitted());
+ opA->check();
+ opB->check();
+ opC->check();
+ }
+
+ void 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));
+
+ CPPUNIT_ASSERT(!buffer.commitLocal(&store));
+ CPPUNIT_ASSERT(store.isAborted());
+ store.check();
+ opA->check();
+ opB->check();
+ opC->check();
+ }
+
+ void 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));
+
+ CPPUNIT_ASSERT(buffer.prepare(0));
+ opA->check();
+ opB->check();
+ opC->check();
+ }
+
+ void 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));
+
+ CPPUNIT_ASSERT(!buffer.prepare(0));
+ opA->check();
+ opB->check();
+ opC->check();
+ }
+
+ void 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();
+ }
+
+ void 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();
+ }
+
+ void 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();
+ }
+};
+
+// Make this test suite a plugin.
+CPPUNIT_PLUGIN_IMPLEMENT();
+CPPUNIT_TEST_SUITE_REGISTRATION(TxBufferTest);
+
diff --git a/qpid/cpp/src/tests/TxMocks.h b/qpid/cpp/src/tests/TxMocks.h
new file mode 100644
index 0000000000..127a27c005
--- /dev/null
+++ b/qpid/cpp/src/tests/TxMocks.h
@@ -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.
+ *
+ */
+#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()){
+ CPPUNIT_ASSERT_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]));
+ }
+ CPPUNIT_ASSERT_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);
+ }
+ ~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/qpid/cpp/src/tests/TxPublishTest.cpp b/qpid/cpp/src/tests/TxPublishTest.cpp
new file mode 100644
index 0000000000..af7761acee
--- /dev/null
+++ b/qpid/cpp/src/tests/TxPublishTest.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/broker/NullMessageStore.h"
+#include "qpid/broker/RecoveryManager.h"
+#include "qpid/broker/TxPublish.h"
+#include "qpid_test_plugin.h"
+#include <iostream>
+#include <list>
+#include <vector>
+#include "MessageUtils.h"
+
+using std::list;
+using std::pair;
+using std::vector;
+using boost::intrusive_ptr;
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+class TxPublishTest : public CppUnit::TestCase
+{
+ typedef std::pair<string, intrusive_ptr<PersistableMessage> > msg_queue_pair;
+
+ class TestMessageStore : public NullMessageStore
+ {
+ public:
+ vector<msg_queue_pair> enqueued;
+
+ void enqueue(TransactionContext*, intrusive_ptr<PersistableMessage>& msg, const PersistableQueue& queue)
+ {
+ msg->enqueueComplete();
+ enqueued.push_back(msg_queue_pair(queue.getName(), msg));
+ }
+
+ //dont care about any of the other methods:
+ TestMessageStore() : NullMessageStore(false) {}
+ ~TestMessageStore(){}
+ };
+
+ CPPUNIT_TEST_SUITE(TxPublishTest);
+ CPPUNIT_TEST(testPrepare);
+ CPPUNIT_TEST(testCommit);
+ CPPUNIT_TEST_SUITE_END();
+
+
+ TestMessageStore store;
+ Queue::shared_ptr queue1;
+ Queue::shared_ptr queue2;
+ intrusive_ptr<Message> msg;
+ TxPublish op;
+
+public:
+
+ 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);
+ }
+
+ void testPrepare()
+ {
+ intrusive_ptr<PersistableMessage> pmsg = static_pointer_cast<PersistableMessage>(msg);
+ //ensure messages are enqueued in store
+ op.prepare(0);
+ CPPUNIT_ASSERT_EQUAL((size_t) 2, store.enqueued.size());
+ CPPUNIT_ASSERT_EQUAL(string("queue1"), store.enqueued[0].first);
+ CPPUNIT_ASSERT_EQUAL(pmsg, store.enqueued[0].second);
+ CPPUNIT_ASSERT_EQUAL(string("queue2"), store.enqueued[1].first);
+ CPPUNIT_ASSERT_EQUAL(pmsg, store.enqueued[1].second);
+ CPPUNIT_ASSERT_EQUAL( true, ( static_pointer_cast<PersistableMessage>(msg))->isEnqueueComplete());
+ }
+
+ void testCommit()
+ {
+ //ensure messages are delivered to queue
+ op.prepare(0);
+ op.commit();
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 1, queue1->getMessageCount());
+ intrusive_ptr<Message> msg_dequeue = queue1->dequeue().payload;
+
+ CPPUNIT_ASSERT_EQUAL( true, (static_pointer_cast<PersistableMessage>(msg_dequeue))->isEnqueueComplete());
+ CPPUNIT_ASSERT_EQUAL(msg, msg_dequeue);
+
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 1, queue2->getMessageCount());
+ CPPUNIT_ASSERT_EQUAL(msg, queue2->dequeue().payload);
+ }
+};
+
+// Make this test suite a plugin.
+CPPUNIT_PLUGIN_IMPLEMENT();
+CPPUNIT_TEST_SUITE_REGISTRATION(TxPublishTest);
+
diff --git a/qpid/cpp/src/tests/Url.cpp b/qpid/cpp/src/tests/Url.cpp
new file mode 100644
index 0000000000..bc07737520
--- /dev/null
+++ b/qpid/cpp/src/tests/Url.cpp
@@ -0,0 +1,64 @@
+/*
+ *
+ * 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)
+
+BOOST_AUTO_TEST_CASE(testUrl_str) {
+ Url url;
+ url.push_back(TcpAddress("foo.com"));
+ url.push_back(TcpAddress("bar.com", 6789));
+ BOOST_CHECK_EQUAL("amqp:tcp:foo.com:5672,tcp:bar.com:6789", url.str());
+ BOOST_CHECK(Url().str().empty());
+}
+
+
+BOOST_AUTO_TEST_CASE(testUrl_parse) {
+ Url url;
+ url.parse("amqp:foo.com,tcp:bar.com:1234");
+ BOOST_CHECK_EQUAL(2u, url.size());
+ BOOST_CHECK_EQUAL("foo.com", boost::get<TcpAddress>(url[0]).host);
+ BOOST_CHECK_EQUAL("amqp:tcp:foo.com:5672,tcp:bar.com:1234", url.str());
+
+ url.parse("amqp:foo/ignorethis");
+ BOOST_CHECK_EQUAL("amqp:tcp:foo:5672", url.str());
+
+ url.parse("amqp:");
+ BOOST_CHECK_EQUAL("amqp:tcp::5672", url.str());
+
+ try {
+ url.parse("invalid url");
+ BOOST_FAIL("Expected InvalidUrl exception");
+ }
+ catch (const Url::InvalidUrl&) {}
+
+ url.parseNoThrow("invalid url");
+ BOOST_CHECK(url.empty());
+}
+
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/Uuid.cpp b/qpid/cpp/src/tests/Uuid.cpp
new file mode 100644
index 0000000000..c158cf53d2
--- /dev/null
+++ b/qpid/cpp/src/tests/Uuid.cpp
@@ -0,0 +1,78 @@
+/*
+ *
+ * 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>
+
+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);
+ }
+};
+
+BOOST_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");
+
+BOOST_AUTO_TEST_CASE(testUuidIstream) {
+ Uuid uuid;
+ istringstream in(sampleStr);
+ in >> uuid;
+ BOOST_CHECK(!in.fail());
+ BOOST_CHECK(uuid == sample);
+}
+
+BOOST_AUTO_TEST_CASE(testUuidOstream) {
+ Uuid uuid(sample.c_array());
+ ostringstream out;
+ out << uuid;
+ BOOST_CHECK(out.good());
+ BOOST_CHECK_EQUAL(out.str(), sampleStr);
+}
+
+BOOST_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/qpid/cpp/src/tests/ais_check b/qpid/cpp/src/tests/ais_check
new file mode 100755
index 0000000000..ae0edf88c1
--- /dev/null
+++ b/qpid/cpp/src/tests/ais_check
@@ -0,0 +1,27 @@
+#!/bin/sh
+# Check for requirements, run AIS tests if found.
+#
+
+id -nG | grep '\<ais\>' || \
+ NOGROUP="You are not a member of the ais 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
+
+echo ./ais_run | newgrp ais
diff --git a/qpid/cpp/src/tests/ais_run b/qpid/cpp/src/tests/ais_run
new file mode 100755
index 0000000000..0f45edc39c
--- /dev/null
+++ b/qpid/cpp/src/tests/ais_run
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# Run AIS tests, assumes that ais_check has passed and we are
+# running with the ais group ID.
+#
+
+# FIXME aconway 2008-01-30: we should valgrind the cluster brokers.
+
+srcdir=`dirname $0`
+$srcdir/start_cluster 4
+./ais_test
+ret=$?
+$srcdir/stop_cluster
+exit $ret
+
diff --git a/qpid/cpp/src/tests/ais_test.cpp b/qpid/cpp/src/tests/ais_test.cpp
new file mode 100644
index 0000000000..00c61242e4
--- /dev/null
+++ b/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/qpid/cpp/src/tests/amqp_0_10/Map.cpp b/qpid/cpp/src/tests/amqp_0_10/Map.cpp
new file mode 100644
index 0000000000..dcba6e38c2
--- /dev/null
+++ b/qpid/cpp/src/tests/amqp_0_10/Map.cpp
@@ -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 "unit_test.h"
+#include "qpid/amqp_0_10/all_built_in_types.h"
+//FIXME aconway 2008-04-08: #include "qpid/amqp_0_10/allSegmentTypes.h"
+#include "qpid/amqp_0_10/Codec.h"
+#include <iostream>
+
+using namespace qpid::amqp_0_10;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(MapTestSuite)
+
+ BOOST_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; }
+};
+
+BOOST_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&) {}
+}
+
+
+BOOST_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");
+}
+
+BOOST_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/qpid/cpp/src/tests/amqp_0_10/ProxyTemplate.cpp b/qpid/cpp/src/tests/amqp_0_10/ProxyTemplate.cpp
new file mode 100644
index 0000000000..cab87b6511
--- /dev/null
+++ b/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> {};
+
+BOOST_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/qpid/cpp/src/tests/amqp_0_10/apply.cpp b/qpid/cpp/src/tests/amqp_0_10/apply.cpp
new file mode 100644
index 0000000000..450aeac356
--- /dev/null
+++ b/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; }
+};
+
+BOOST_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; }
+};
+
+BOOST_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/qpid/cpp/src/tests/amqp_0_10/handlers.cpp b/qpid/cpp/src/tests/amqp_0_10/handlers.cpp
new file mode 100644
index 0000000000..035429a15d
--- /dev/null
+++ b/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); }
+};
+
+BOOST_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/qpid/cpp/src/tests/amqp_0_10/serialize.cpp b/qpid/cpp/src/tests/amqp_0_10/serialize.cpp
new file mode 100644
index 0000000000..8928a9fbc9
--- /dev/null
+++ b/qpid/cpp/src/tests/amqp_0_10/serialize.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 "unit_test.h"
+#include "tests/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/StructHolder.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.
+BOOST_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);
+}
+
+BOOST_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");
+}
+
+BOOST_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); }
+};
+
+BOOST_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');
+}
+
+BOOST_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);
+}
+
+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); }
+
+BOOST_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);
+}
+
+
+BOOST_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');
+}
+
+BOOST_AUTO_TEST_CASE(testUnit) {
+ 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);
+}
+
+BOOST_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);
+}
+
+BOOST_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);
+ uint16_t encodedBits=uint8_t(data[1]); // Little-endian
+ encodedBits <<= 8;
+ encodedBits += uint8_t(data[0]);
+ BOOST_CHECK_EQUAL(encodedBits, packBits(dp));
+
+ data.clear();
+ Struct::Holder h(dp);
+ Codec::encode(back_inserter(data))(h);
+
+ Struct::Holder 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);
+ using qpid::framing::Buffer;
+ using qpid::framing::AMQFrame;
+
+ Unit u(t);
+ connection::Start s;
+
+ string data;
+ Codec::encode(back_inserter(data))(u.getHeader())(u);
+ data.push_back(char(0xCE)); // Preview end-of-frame
+
+ Buffer buf(&data[0], data.size());
+ AMQFrame f;
+ f.decode(buf);
+
+ string data2(f.size(), ' ');
+ Buffer buf2(&data2[0], data.size());
+ f.encode(buf2);
+
+ BOOST_CHECK_MESSAGE(data == data2, BOOST_CURRENT_FUNCTION);
+ BOOST_CHECK_EQUAL(data, data2);
+
+ Codec::Decoder<string::iterator> decode(data2.begin());
+ FrameHeader h;
+ decode(h);
+ Unit u2(h);
+ decode(u2);
+
+ string data3;
+ Codec::encode(back_inserter(data3))(u.getHeader())(u);
+
+ BOOST_CHECK_EQUAL(data3, data2);
+ BOOST_CHECK_MESSAGE(data3 == data2, BOOST_CURRENT_FUNCTION);
+ }
+};
+
+// BOOST_AUTO_TEST_CASE(testSerializeAllSegmentTypes) {
+// RecodeUnit recode;
+// allSegmentTypes(recode);
+// }
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/client_test.cpp b/qpid/cpp/src/tests/client_test.cpp
new file mode 100644
index 0000000000..bd2a541c92
--- /dev/null
+++ b/qpid/cpp/src/tests/client_test.cpp
@@ -0,0 +1,147 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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/MessageTransferBody.h"
+
+using namespace qpid;
+using namespace qpid::client;
+using qpid::framing::FrameSet;
+using qpid::framing::MessageTransferBody;
+using std::string;
+
+struct Args : public qpid::TestOptions {
+ uint msgSize;
+ uint maxFrameSize;
+
+ Args() : msgSize(26), maxFrameSize(65535)
+ {
+ addOptions()
+ ("size", optValue(msgSize, "N"), "message size")
+ ("max-frame-size", optValue(maxFrameSize, "N"), "max frame size");
+ }
+};
+
+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.trace, opts.maxFrameSize);
+ opts.open(connection);
+ if (opts.trace) std::cout << "Opened connection." << std::endl;
+
+ //Create and open a session on the connection through which
+ //most functionality is exposed:
+ Session session = connection.newSession(ASYNC);
+ if (opts.trace) 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.trace) std::cout << "Declared exchange." << std::endl;
+ session.queueDeclare(arg::queue="MyQueue", arg::autoDelete=true, arg::exclusive=true);
+ if (opts.trace) std::cout << "Declared queue." << std::endl;
+
+ //now bind the queue to the exchange
+ session.queueBind(arg::exchange="MyExchange", arg::queue="MyQueue", arg::routingKey="MyKey");
+ if (opts.trace) 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);
+ if (opts.trace) 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.trace) std::cout << "Subscribed to queue." << std::endl;
+ FrameSet::shared_ptr incoming = session.get();
+ if (incoming->isA<MessageTransferBody>()) {
+ Message msgIn(*incoming, session);
+ if (msgIn.getData() == msgOut.getData()) {
+ if (opts.trace) std::cout << "Received the exepected message." << std::endl;
+ msgIn.acknowledge();
+ } else {
+ print("Received an unexepected message: ", msgIn);
+ }
+ }
+
+ //close the session & connection
+ session.close();
+ if (opts.trace) std::cout << "Closed session." << std::endl;
+ connection.close();
+ if (opts.trace) std::cout << "Closed connection." << std::endl;
+ return 0;
+ } catch(const std::exception& e) {
+ std::cout << e.what() << std::endl;
+ }
+ return 1;
+}
diff --git a/qpid/cpp/src/tests/cluster.mk b/qpid/cpp/src/tests/cluster.mk
new file mode 100644
index 0000000000..ba8d99935f
--- /dev/null
+++ b/qpid/cpp/src/tests/cluster.mk
@@ -0,0 +1,20 @@
+if CPG
+#
+# Cluster tests makefile fragment, to be included in Makefile.am
+#
+
+lib_cluster = $(abs_builddir)/../libqpidcluster.la
+
+# 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 conditions for AIS tests and runs if ok.
+TESTS+=ais_check
+EXTRA_DIST+=ais_check ais_run
+
+check_PROGRAMS+=ais_test
+ais_test_SOURCES=ais_test.cpp Cpg.cpp
+ais_test_LDADD=$(lib_client) $(lib_cluster) -lboost_unit_test_framework
+
+endif
diff --git a/qpid/cpp/src/tests/cluster_client.cpp b/qpid/cpp/src/tests/cluster_client.cpp
new file mode 100644
index 0000000000..cd048d1651
--- /dev/null
+++ b/qpid/cpp/src/tests/cluster_client.cpp
@@ -0,0 +1,84 @@
+/*
+ *
+ * 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 "BrokerFixture.h"
+#include "qpid/client/Session.h"
+
+#include <fstream>
+#include <vector>
+#include <functional>
+
+QPID_AUTO_TEST_SUITE(cluster_clientTestSuite)
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace qpid::framing;
+using namespace qpid::client::arg;
+using framing::TransferContent;
+using std::vector;
+using std::string;
+using std::ifstream;
+using std::ws;
+
+struct ClusterConnections : public vector<shared_ptr<Connection> > {
+ ClusterConnections() {
+ ifstream portfile("cluster.ports");
+ BOOST_REQUIRE(portfile.good());
+ portfile >> ws;
+ while (portfile.good()) {
+ uint16_t port;
+ portfile >> port >> ws;
+ push_back(make_shared_ptr(new Connection(port)));
+ back()->open("localhost", port);
+ }
+ BOOST_REQUIRE(size() > 1);
+ }
+
+ ~ClusterConnections() {
+ for (iterator i = begin(); i != end(); ++i ){
+ (*i)->close();
+ }
+ }
+};
+
+BOOST_AUTO_TEST_CASE(testWiringReplication) {
+ // Declare on one broker, use on others.
+ ClusterConnections cluster;
+ BOOST_REQUIRE(cluster.size() > 1);
+
+ Session broker0 = cluster[0]->newSession(ASYNC);
+ broker0.exchangeDeclare(exchange="ex");
+ broker0.queueDeclare(queue="q");
+ broker0.queueBind(exchange="ex", queue="q", routingKey="key");
+ broker0.close();
+
+ for (size_t i = 1; i < cluster.size(); ++i) {
+ Session s = cluster[i]->newSession(ASYNC);
+ s.messageTransfer(content=TransferContent("data", "key", "ex"));
+ s.messageSubscribe(queue="q", destination="q");
+ s.messageFlow(destination="q", unit=0, value=1);//messages
+ FrameSet::shared_ptr msg = s.get();
+ BOOST_CHECK(msg->isA<MessageTransferBody>());
+ BOOST_CHECK_EQUAL(string("data"), msg->getContent());
+ s.getExecution().completed(msg->getId(), true, true);
+ cluster[i]->close();
+ }
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/dlclose_noop.c b/qpid/cpp/src/tests/dlclose_noop.c
new file mode 100644
index 0000000000..ba2fa75891
--- /dev/null
+++ b/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/qpid/cpp/src/tests/echo_service.cpp b/qpid/cpp/src/tests/echo_service.cpp
new file mode 100644
index 0000000000..c3569d5fd4
--- /dev/null
+++ b/qpid/cpp/src/tests/echo_service.cpp
@@ -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.
+ *
+ */
+
+/**
+ * This class provides an example of using AMQP for a request-response
+ * style system. 'Requests' are messages sent to a well known
+ * destination. A 'service' process consumes these message and
+ * responds by echoing the message back to the sender on a
+ * sender-specified private queue.
+ */
+
+#include "qpid/client/Channel.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Exchange.h"
+#include "qpid/client/MessageListener.h"
+#include "qpid/client/Queue.h"
+#include "qpid/sys/Time.h"
+#include <iostream>
+#include <sstream>
+
+using namespace qpid::client;
+using namespace qpid::sys;
+using std::string;
+
+
+/**
+ * A message listener implementation representing the 'service', this
+ * will 'echo' any requests received.
+ */
+class EchoServer : public MessageListener{
+ Channel* const channel;
+public:
+ EchoServer(Channel* channel);
+ virtual void received(Message& msg);
+};
+
+/**
+ * A message listener implementation that merely prints received
+ * messages to the console. Used to report on 'echo' responses.
+ */
+class LoggingListener : public MessageListener{
+public:
+ virtual void received(Message& msg);
+};
+
+/**
+ * A utility class that manages the command line options needed to run
+ * the example confirgurably.
+ */
+class Args{
+ string host;
+ int port;
+ bool trace;
+ bool help;
+ bool client;
+public:
+ inline Args() : host("localhost"), port(5672), trace(false), help(false), client(false){}
+ void parse(int argc, char** argv);
+ void usage();
+
+ inline const string& getHost() const { return host;}
+ inline int getPort() const { return port; }
+ inline bool getTrace() const { return trace; }
+ inline bool getHelp() const { return help; }
+ inline bool getClient() const { return client; }
+};
+
+/**
+ * The main test path. There are two basic modes: 'client' and
+ * 'service'. First one or more services are started, then one or more
+ * clients are started and messages can be sent.
+ */
+int main(int argc, char** argv){
+ const std::string echo_service("echo_service");
+ Args args;
+ args.parse(argc, argv);
+ if (args.getHelp()) {
+ args.usage();
+ } else if (args.getClient()) {
+ //we have been started in 'client' mode, i.e. we will send an
+ //echo requests and print responses received.
+ try {
+ //Create connection & open a channel
+ Connection connection(args.getTrace());
+ connection.open(args.getHost(), args.getPort());
+ Channel channel;
+ connection.openChannel(channel);
+
+ //Setup: declare the private 'response' queue and bind it
+ //to the direct exchange by its name which will be
+ //generated by the server
+ Queue response;
+ channel.declareQueue(response);
+ qpid::framing::FieldTable emptyArgs;
+ channel.bind(Exchange::STANDARD_DIRECT_EXCHANGE, response, response.getName(), emptyArgs);
+
+ //Consume from the response queue, logging all echoed message to console:
+ LoggingListener listener;
+ std::string tag;
+ channel.consume(response, tag, &listener);
+
+ //Process incoming requests on a new thread
+ channel.start();
+
+ //get messages from console and send them:
+ std::string text;
+ std::cout << "Enter text to send:" << std::endl;
+ while (std::getline(std::cin, text)) {
+ std::cout << "Sending " << text << " to echo server." << std::endl;
+ Message msg;
+ msg.getHeaders().setString("RESPONSE_QUEUE", response.getName());
+ msg.setData(text);
+ channel.publish(msg, Exchange::STANDARD_DIRECT_EXCHANGE, echo_service);
+
+ std::cout << "Enter text to send:" << std::endl;
+ }
+
+ connection.close();
+ } catch(std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ } else {
+ // we are in 'service' mode, i.e. we will consume messages
+ // from the request queue and echo each request back to the
+ // senders own private response queue.
+ try {
+ //Create connection & open a channel
+ Connection connection(args.getTrace());
+ connection.open(args.getHost(), args.getPort());
+ Channel channel;
+ connection.openChannel(channel);
+
+ //Setup: declare the 'request' queue and bind it to the direct exchange with a 'well known' name
+ Queue request("request");
+ channel.declareQueue(request);
+ qpid::framing::FieldTable emptyArgs;
+ channel.bind(Exchange::STANDARD_DIRECT_EXCHANGE, request, echo_service, emptyArgs);
+
+ //Consume from the request queue, echoing back all messages received to the client that sent them
+ EchoServer server(&channel);
+ std::string tag = "server_tag";
+ channel.consume(request, tag, &server);
+
+ //Process incoming requests on the main thread
+ channel.run();
+
+ connection.close();
+ } catch(std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ }
+}
+
+EchoServer::EchoServer(Channel* _channel) : channel(_channel){}
+
+void EchoServer::received(Message& message)
+{
+ //get name of response queues binding to the default direct exchange:
+ const std::string name = message.getHeaders().getString("RESPONSE_QUEUE");
+
+ if (name.empty()) {
+ std::cout << "Cannot echo " << message.getData() << ", no response queue specified." << std::endl;
+ } else {
+ //print message to console:
+ std::cout << "Echoing " << message.getData() << " back to " << name << std::endl;
+
+ //'echo' the message back:
+ channel->publish(message, Exchange::STANDARD_DIRECT_EXCHANGE, name);
+ }
+}
+
+void LoggingListener::received(Message& message)
+{
+ //print message to console:
+ std::cout << "Received echo: " << message.getData() << std::endl;
+}
+
+
+void Args::parse(int argc, char** argv){
+ for(int i = 1; i < argc; i++){
+ string name(argv[i]);
+ if("-help" == name){
+ help = true;
+ break;
+ }else if("-host" == name){
+ host = argv[++i];
+ }else if("-port" == name){
+ port = atoi(argv[++i]);
+ }else if("-trace" == name){
+ trace = true;
+ }else if("-client" == name){
+ client = true;
+ }else{
+ std::cout << "Warning: unrecognised option " << name << std::endl;
+ }
+ }
+}
+
+void Args::usage(){
+ std::cout << "Options:" << std::endl;
+ std::cout << " -help" << std::endl;
+ std::cout << " Prints this usage message" << std::endl;
+ std::cout << " -host <host>" << std::endl;
+ std::cout << " Specifies host to connect to (default is localhost)" << std::endl;
+ std::cout << " -port <port>" << std::endl;
+ std::cout << " Specifies port to conect to (default is 5762)" << std::endl;
+ std::cout << " -trace" << std::endl;
+ std::cout << " Indicates that the frames sent and received should be logged" << std::endl;
+ std::cout << " -client" << std::endl;
+ std::cout << " Run as a client (else will run as a server)" << std::endl;
+}
diff --git a/qpid/cpp/src/tests/exception_test.cpp b/qpid/cpp/src/tests/exception_test.cpp
new file mode 100644
index 0000000000..715cdaec2a
--- /dev/null
+++ b/qpid/cpp/src/tests/exception_test.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/SubscriptionManager.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/sys/Thread.h"
+#include "qpid/framing/reply_exceptions.h"
+
+QPID_AUTO_TEST_SUITE(exception_test)
+
+
+using namespace std;
+using namespace qpid;
+using namespace sys;
+using namespace client;
+using namespace framing;
+
+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 { f(); }
+ catch(const Ex& e) {
+ caught=true;
+ BOOST_MESSAGE(string("Caught expected exception: ")+e.what());
+ }
+ catch(const std::exception& e) {
+ BOOST_ERROR(string("Bad exception: ")+e.what());
+ }
+ catch(...) {
+ BOOST_ERROR(string("Bad exception: unknown"));
+ }
+ }
+
+ bool join() {
+ if (thread.id()) {
+ thread.join();
+ thread=Thread();
+ }
+ return caught;
+ }
+};
+
+BOOST_FIXTURE_TEST_CASE(DisconnectedPop, ProxySessionFixture) {
+ ProxyConnection c(broker->getPort());
+ session.queueDeclare(arg::queue="q");
+ subs.subscribe(lq, "q");
+ Catcher<ClosedException> pop(bind(&LocalQueue::pop, boost::ref(lq)));
+ connection.proxy.close();
+ BOOST_CHECK(pop.join());
+}
+
+BOOST_FIXTURE_TEST_CASE(DisconnectedListen, ProxySessionFixture) {
+ struct NullListener : public MessageListener {
+ void received(Message&) { BOOST_FAIL("Unexpected message"); }
+ } l;
+ ProxyConnection c(broker->getPort());
+ session.queueDeclare(arg::queue="q");
+ subs.subscribe(l, "q");
+ Thread t(subs);
+ connection.proxy.close();
+ t.join();
+ BOOST_CHECK_THROW(session.close(), InternalErrorException);
+}
+
+BOOST_FIXTURE_TEST_CASE(NoSuchQueueTest, ProxySessionFixture) {
+ BOOST_CHECK_THROW(subs.subscribe(lq, "no such queue").sync(), NotFoundException);
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/fanout_perftest b/qpid/cpp/src/tests/fanout_perftest
new file mode 100755
index 0000000000..602aac25b7
--- /dev/null
+++ b/qpid/cpp/src/tests/fanout_perftest
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec `dirname $0`/run_perftest 10000 --mode fanout --npubs 16 --nsubs 16
diff --git a/qpid/cpp/src/tests/federation.py b/qpid/cpp/src/tests/federation.py
new file mode 100755
index 0000000000..28ebc4a24d
--- /dev/null
+++ b/qpid/cpp/src/tests/federation.py
@@ -0,0 +1,191 @@
+#!/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 TestBase, testrunner
+from qpid.management import managementChannel, managementClient
+from qpid.queue import Empty
+from qpid.content import Content
+
+
+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 Helper:
+ def __init__(self, parent):
+ self.parent = parent
+ self.channel = parent.client.channel(2)
+ self.mc = managementClient(self.channel.spec)
+ self.mch = self.mc.addChannel(self.channel)
+ self.mc.syncWaitForStable(self.mch)
+
+ def get_objects(self, type):
+ return self.mc.syncGetObjects(self.mch, type)
+
+ def get_object(self, type, position = 1, expected = None):
+ objects = self.get_objects(type)
+ if not expected: expected = position
+ self.assertEqual(len(objects), expected)
+ return objects[(position - 1)]
+
+
+ def call_method(self, object, method, args=None):
+ res = self.mc.syncCallMethod(self.mch, object.id, object.classKey, method, args)
+ self.assertEqual(res.status, 0)
+ self.assertEqual(res.statusText, "OK")
+ return res
+
+ def assertEqual(self, a, b):
+ self.parent.assertEqual(a, b)
+
+class FederationTests(TestBase):
+
+ def test_bridge_create_and_close(self):
+ mgmt = Helper(self)
+ broker = mgmt.get_object("broker")
+
+ for i in range(10):
+ mgmt.call_method(broker, "connect", {"host":remote_host(), "port":remote_port()})
+ link = mgmt.get_object("link")
+
+ mgmt.call_method(link, "bridge", {"src":"amq.direct", "dest":"amq.direct", "key":"my-key"})
+ bridge = mgmt.get_object("bridge")
+
+ mgmt.call_method(bridge, "close")
+ self.assertEqual(len(mgmt.get_objects("bridge")), 0)
+
+ mgmt.call_method(link, "close")
+ self.assertEqual(len(mgmt.get_objects("link")), 0)
+
+ def test_pull_from_exchange(self):
+ channel = self.channel
+
+ mgmt = Helper(self)
+ broker = mgmt.get_object("broker")
+
+ mgmt.call_method(broker, "connect", {"host":remote_host(), "port":remote_port()})
+ link = mgmt.get_object("link")
+
+ mgmt.call_method(link, "bridge", {"src":"amq.direct", "dest":"amq.fanout", "key":"my-key"})
+ bridge = mgmt.get_object("bridge")
+
+ #setup queue to receive messages from local broker
+ channel.queue_declare(queue="fed1", exclusive=True, auto_delete=True)
+ channel.queue_bind(queue="fed1", exchange="amq.fanout")
+ self.subscribe(queue="fed1", destination="f1")
+ queue = self.client.queue("f1")
+
+ #send messages to remote broker and confirm it is routed to local broker
+ r_conn = self.connect(host=remote_host(), port=remote_port())
+ r_channel = r_conn.channel(1)
+ r_channel.session_open()
+
+ for i in range(1, 11):
+ r_channel.message_transfer(destination="amq.direct", content=Content(properties={'routing_key' : "my-key"}, body="Message %d" % i))
+
+ for i in range(1, 11):
+ msg = queue.get(timeout=5)
+ self.assertEqual("Message %d" % i, msg.content.body)
+ try:
+ extra = queue.get(timeout=1)
+ self.fail("Got unexpected message in queue: " + extra.content.body)
+ except Empty: None
+
+
+ mgmt.call_method(bridge, "close")
+ self.assertEqual(len(mgmt.get_objects("bridge")), 0)
+
+ mgmt.call_method(link, "close")
+ self.assertEqual(len(mgmt.get_objects("link")), 0)
+
+ def test_pull_from_queue(self):
+ channel = self.channel
+
+ #setup queue on remote broker and add some messages
+ r_conn = self.connect(host=remote_host(), port=remote_port())
+ r_channel = r_conn.channel(1)
+ r_channel.session_open()
+ r_channel.queue_declare(queue="my-bridge-queue", exclusive=True, auto_delete=True)
+ for i in range(1, 6):
+ r_channel.message_transfer(content=Content(properties={'routing_key' : "my-bridge-queue"}, body="Message %d" % i))
+
+ #setup queue to receive messages from local broker
+ channel.queue_declare(queue="fed1", exclusive=True, auto_delete=True)
+ channel.queue_bind(queue="fed1", exchange="amq.fanout")
+ self.subscribe(queue="fed1", destination="f1")
+ queue = self.client.queue("f1")
+
+ mgmt = Helper(self)
+ broker = mgmt.get_object("broker")
+
+ mgmt.call_method(broker, "connect", {"host":remote_host(), "port":remote_port()})
+ link = mgmt.get_object("link")
+
+ mgmt.call_method(link, "bridge", {"src":"my-bridge-queue", "dest":"amq.fanout", "key":"", "src_is_queue":1})
+ bridge = mgmt.get_object("bridge")
+
+ #add some more messages (i.e. after bridge was created)
+ for i in range(6, 11):
+ r_channel.message_transfer(content=Content(properties={'routing_key' : "my-bridge-queue"}, body="Message %d" % i))
+
+ for i in range(1, 11):
+ msg = queue.get(timeout=5)
+ self.assertEqual("Message %d" % i, msg.content.body)
+ try:
+ extra = queue.get(timeout=1)
+ self.fail("Got unexpected message in queue: " + extra.content.body)
+ except Empty: None
+
+
+ mgmt.call_method(bridge, "close")
+ self.assertEqual(len(mgmt.get_objects("bridge")), 0)
+
+ mgmt.call_method(link, "close")
+ self.assertEqual(len(mgmt.get_objects("link")), 0)
+
+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)
+ #add module(s) to run to testrunners args
+ args.append("federation")
+
+ if not testrunner.run(args): sys.exit(1)
diff --git a/qpid/cpp/src/tests/interop_runner.cpp b/qpid/cpp/src/tests/interop_runner.cpp
new file mode 100644
index 0000000000..824af7f3b7
--- /dev/null
+++ b/qpid/cpp/src/tests/interop_runner.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 "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/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::TestOptions;
+using qpid::framing::FieldTable;
+using qpid::framing::ReplyTo;
+using namespace std;
+
+class DummyRun : public TestCase
+{
+public:
+ DummyRun() {}
+ void assign(const string&, FieldTable&, TestOptions&) {}
+ 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;
+ TestOptions& 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, TestOptions& options);
+ void received(Message& msg);
+ void bindAndConsume();
+ void registerTest(string name, TestCase* test);
+};
+
+int main(int argc, char** argv) {
+ try {
+ TestOptions options;
+ options.parse(argc, argv);
+ if (options.help)
+ cout << options;
+ else {
+ Connection connection(options.trace);
+ 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, TestOptions& _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.getExchangeName();
+ 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::get_pointer(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/qpid/cpp/src/tests/latencytest.cpp b/qpid/cpp/src/tests/latencytest.cpp
new file mode 100644
index 0000000000..2b44a5477a
--- /dev/null
+++ b/qpid/cpp/src/tests/latencytest.cpp
@@ -0,0 +1,372 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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 <unistd.h>
+
+#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 std::string;
+
+typedef std::vector<std::string> StringSet;
+
+struct Args : public qpid::TestOptions {
+ uint size;
+ uint count;
+ uint rate;
+ uint reportFrequency;
+ uint queues;
+ uint prefetch;
+ uint ack;
+ bool durable;
+ string base;
+
+ Args() : size(256), count(1000), rate(0), reportFrequency(1), 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)")
+ ("report-frequency", optValue(reportFrequency, "N"),
+ "number of seconds to wait between reports (ignored unless rate specified)")
+ ("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")
+ ("queue-base-name", optValue(base, "<name>"), "base name for queues");
+ }
+};
+
+const std::string chars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
+
+Args opts;
+
+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;
+ Session 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();
+};
+
+
+class Sender : public Client
+{
+ string generateData(uint size);
+ void sendByRate();
+ void sendByCount();
+public:
+ Sender(const string& queue);
+ 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), begin(now()) {}
+ void start();
+ void join();
+ void report();
+};
+
+
+Client::Client(const string& q) : queue(q)
+{
+ opts.open(connection);
+ session = connection.newSession(ASYNC);
+}
+
+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);
+ }
+ if (opts.prefetch) {
+ mgr.setAckPolicy(AckPolicy(opts.ack ? opts.ack : (opts.prefetch / 2)));
+ mgr.setFlowControl(opts.prefetch, SubscriptionManager::UNLIMITED, true);
+ } else {
+ mgr.setConfirmMode(false);
+ mgr.setFlowControl(SubscriptionManager::UNLIMITED, SubscriptionManager::UNLIMITED, false);
+ }
+ mgr.subscribe(*this, queue);
+}
+
+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();
+
+ 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++;
+ if (minLatency == 0 || minLatency > latency) minLatency = latency;
+ if (maxLatency == 0 || maxLatency < latency) maxLatency = latency;
+ totalLatency += latency;
+}
+
+Stats::Stats() : count(0), minLatency(0), maxLatency(0), totalLatency(0) {}
+
+void Stats::print()
+{
+ Mutex::ScopedLock l(lock);
+ std::cout << "Latency(ms): min=" << minLatency << ", max=" << maxLatency << ", avg=" << (totalLatency / count);
+}
+
+void Stats::reset()
+{
+ Mutex::ScopedLock l(lock);
+ count = 0;
+ totalLatency = maxLatency = minLatency = 0;
+}
+
+Sender::Sender(const string& q) : Client(q) {}
+
+void Sender::test()
+{
+ if (opts.rate) sendByRate();
+ else sendByCount();
+}
+
+void Sender::sendByCount()
+{
+ Message msg(generateData(opts.size), queue);
+ if (opts.durable) {
+ msg.getDeliveryProperties().setDeliveryMode(framing::PERSISTENT);
+ }
+
+ Completion c;
+ for (uint i = 0; i < opts.count; i++) {
+ uint64_t sentAt(current_time());
+ msg.getDeliveryProperties().setTimestamp(sentAt);
+ //msg.getHeaders().setTimestamp("sent-at", sentAt);//TODO add support for uint64_t to field tables
+ c = session.messageTransfer(arg::content=msg);
+ }
+ c.sync();
+}
+
+void Sender::sendByRate()
+{
+ Message msg(generateData(opts.size), queue);
+ if (opts.durable) {
+ msg.getDeliveryProperties().setDeliveryMode(framing::PERSISTENT);
+ }
+
+ //calculate metrics required for target rate
+ uint msgsPerMsec = opts.rate / 1000;
+
+ while (true) {
+ uint64_t start(current_time());
+ for (uint i = 0; i < msgsPerMsec; i++) {
+ uint64_t sentAt(current_time());
+ msg.getDeliveryProperties().setTimestamp(sentAt);
+ //msg.getHeaders().setTimestamp("sent-at", sentAt);//TODO add support for uint64_t to field tables
+ session.messageTransfer(arg::content=msg);
+ }
+ uint64_t timeTaken = (current_time() - start) / TIME_USEC;
+ if (timeTaken < 1000) {
+ usleep(1000 - timeTaken);
+ } else if (timeTaken > 1000) {
+ double timeMsecs = (double) timeTaken / 1000;
+ std::cout << "Could not achieve desired rate. Sent " << msgsPerMsec << " in "
+ << (timeMsecs) << "ms (" << ((msgsPerMsec * 1000 * 1000) / timeTaken) << " msgs/s)" << 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);
+ std::cout << "Sent " << opts.count << " msgs through " << queue
+ << " in " << msecs << "ms (" << (opts.count * 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);
+ 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) {
+ while (true) {
+ usleep(opts.reportFrequency * 1000 * 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/qpid/cpp/src/tests/logging.cpp b/qpid/cpp/src/tests/logging.cpp
new file mode 100644
index 0000000000..718ab01d9a
--- /dev/null
+++ b/qpid/cpp/src/tests/logging.cpp
@@ -0,0 +1,384 @@
+/*
+ *
+ * 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/memory.h"
+#include "qpid/Options.h"
+
+#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;
+
+BOOST_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);
+}
+
+
+BOOST_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"));
+}
+
+BOOST_AUTO_TEST_CASE(testStatementEnabled) {
+ // Verify that the singleton enables and disables static
+ // log statements.
+ Logger& l = Logger::instance();
+ 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;
+
+BOOST_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);
+}
+
+BOOST_AUTO_TEST_CASE(testMacro) {
+ Logger& l=Logger::instance();
+ l.clear();
+ 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);
+}
+
+BOOST_AUTO_TEST_CASE(testLoggerFormat) {
+ Logger& l = Logger::instance();
+ 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");
+
+ l.format(Logger::LEVEL);
+ QPID_LOG(critical, "foo");
+ BOOST_CHECK_EQUAL("critical foo\n", out->last());
+
+ l.format(~0); // Everything
+ QPID_LOG(critical, "foo");
+ string re=".* critical -?\\[[0-9a-f]*] "+string(__FILE__)+":\\d+:void .*testLoggerFormat.*\\(\\): foo\n";
+ BOOST_CHECK_REGEX(re, out->last());
+}
+
+BOOST_AUTO_TEST_CASE(testOstreamOutput) {
+ Logger& l=Logger::instance();
+ l.clear();
+ l.select(Selector(error));
+ ostringstream os;
+ l.output(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.
+BOOST_AUTO_TEST_CASE(testSyslogOutput) {
+ Logger& l=Logger::instance();
+ 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
+BOOST_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*))
+
+BOOST_AUTO_TEST_CASE(testOptionsParse) {
+ const char* argv[]={
+ 0,
+ "--log-enable", "error+:foo",
+ "--log-enable", "debug:bar",
+ "--log-enable", "info",
+ "--log-output", "x",
+ "--log-output", "y",
+ "--log-level", "yes",
+ "--log-source", "1",
+ "--log-thread", "true",
+ "--log-function", "YES"
+ };
+ 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);
+ expect=list_of("x")("y");
+ BOOST_CHECK_EQUAL(expect, opts.outputs);
+ BOOST_CHECK(opts.level);
+ BOOST_CHECK(opts.source);
+ BOOST_CHECK(opts.function);
+ BOOST_CHECK(opts.thread);
+}
+
+BOOST_AUTO_TEST_CASE(testOptionsDefault) {
+ Options opts;
+ vector<string> expect=list_of("stderr");
+ BOOST_CHECK_EQUAL(expect, opts.outputs);
+ expect=list_of("error+");
+ BOOST_CHECK_EQUAL(expect, opts.selectors);
+ BOOST_CHECK(opts.time && opts.level);
+ BOOST_CHECK(!(opts.source || opts.function || opts.thread));
+}
+
+BOOST_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"));
+}
+
+BOOST_AUTO_TEST_CASE(testOptionsFormat) {
+ Logger l;
+ {
+ Options opts;
+ BOOST_CHECK_EQUAL(Logger::TIME|Logger::LEVEL, l.format(opts));
+ const char* argv[]={
+ 0,
+ "--log-time", "no",
+ "--log-level", "no",
+ "--log-source", "1",
+ "--log-thread", "1"
+ };
+ opts.parse(ARGC(argv), const_cast<char**>(argv));
+ BOOST_CHECK_EQUAL(
+ Logger::FILE|Logger::LINE|Logger::THREAD, l.format(opts));
+ }
+ {
+ Options opts; // Clear.
+ const char* argv[]={
+ 0,
+ "--log-level", "no",
+ "--log-thread", "true",
+ "--log-function", "YES",
+ "--log-time", "YES"
+ };
+ opts.parse(ARGC(argv), const_cast<char**>(argv));
+ BOOST_CHECK_EQUAL(
+ Logger::THREAD|Logger::FUNCTION|Logger::TIME,
+ l.format(opts));
+ }
+}
+
+BOOST_AUTO_TEST_CASE(testLoggerConfigure) {
+ Logger& l=Logger::instance();
+ l.clear();
+ Options opts;
+ const char* argv[]={
+ 0,
+ "--log-time", "no",
+ "--log-source", "yes",
+ "--log-output", "logging.tmp",
+ "--log-enable", "critical"
+ };
+ opts.parse(ARGC(argv), const_cast<char**>(argv));
+ l.configure(opts, "test");
+ 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");
+}
+
+BOOST_AUTO_TEST_CASE(testQuoteNonPrintable) {
+ Logger& l=Logger::instance();
+ l.clear();
+ Options opts;
+ opts.outputs.clear();
+ opts.outputs.push_back("logging.tmp");
+ opts.time=false;
+ l.configure(opts, "test");
+ 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);
+ string expect="critical null\\00tab\\09space newline\\0Aret\\0D\\80\\99\\FF\\00";
+ BOOST_CHECK_EQUAL(expect, line);
+ log.close();
+ unlink("logging.tmp");
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/multiq_perftest b/qpid/cpp/src/tests/multiq_perftest
new file mode 100755
index 0000000000..f6644e740c
--- /dev/null
+++ b/qpid/cpp/src/tests/multiq_perftest
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec `dirname $0`/run_perftest 10000 --mode shared --qt 16
diff --git a/qpid/cpp/src/tests/perfdist b/qpid/cpp/src/tests/perfdist
new file mode 100755
index 0000000000..816d2d99f6
--- /dev/null
+++ b/qpid/cpp/src/tests/perfdist
@@ -0,0 +1,50 @@
+#!/bin/bash
+#
+# Distributed perftest.
+# Runs perftest clients on multiple hosts using ssh.
+#
+
+set -e
+usage() {
+cat <<EOF
+usage: $0 <perftest-args> -- <client-hosts ...>
+
+Run perftest with clients running on the listed hosts. Clients are
+assigned to hosts publishers first, then subscribers the host list is
+used round-robin if there are more clients than hosts. perftest-args should
+include a --host <brokerhost> flag.
+
+Do not pass preftest action flags: --setup, --control, --publish, --subscribe.
+The script will pass them to the appropriate client processes.
+
+Note all perftest args must come before --.
+
+Error: $*
+EOF
+exit 1
+}
+
+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 ;;
+ --) COLLECT=HOSTS; shift ;;
+ *) collect $1; shift ;;
+ esac
+done
+if [ -z "$HOSTS" ]; then usage "No hosts listed after --"; fi
+PATH="`dirname $0`:$PATH"
+PERFTEST="`which perftest` $ARGS" || usage "Can't find perftest executable"
+
+HOSTS=($HOSTS)
+start() { ssh ${HOSTS[i % ${#HOSTS[*]}]} $PERFTEST $*& }
+
+$PERFTEST --setup
+for (( i=0 ; i < $NPUBS ; ++i)); do start --publish; done
+for (( ; i < $NPUBS+$NSUBS ; ++i)); do start --subscribe; done
+$PERFTEST --control
diff --git a/qpid/cpp/src/tests/perftest.cpp b/qpid/cpp/src/tests/perftest.cpp
new file mode 100644
index 0000000000..b950e432f5
--- /dev/null
+++ b/qpid/cpp/src/tests/perftest.cpp
@@ -0,0 +1,640 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/Session.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>
+
+
+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;
+
+ // Publisher
+ size_t pubs;
+ size_t count ;
+ size_t size;
+ bool confirm;
+ bool durable;
+ bool uniqueData;
+
+ // Subscriber
+ size_t subs;
+ size_t ack;
+
+ // General
+ size_t qt;
+ size_t iterations;
+ Mode mode;
+ bool summary;
+ uint32_t intervalSub;
+ uint32_t intervalPub;
+
+ 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),
+ subs(1), ack(0),
+ qt(1), iterations(1), mode(SHARED), summary(false),
+ intervalSub(0), intervalPub(0)
+ {
+ 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.")
+
+ ("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'")
+
+ ("interval_sub", optValue(intervalSub, "ms"), ">=0 delay between msg consume")
+ ("interval_pub", optValue(intervalPub, "ms"), ">=0 delay between msg publish");
+ }
+
+ // 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);
+ }
+};
+
+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;
+ Session session;
+ Thread thread;
+
+ Client() {
+ opts.open(connection);
+ session = connection.newSession(ASYNC);
+ }
+
+ ~Client() {
+ session.close();
+ connection.close();
+ }
+};
+
+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).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, 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);
+ }
+
+ 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;
+ exit(1);
+ }
+ }
+};
+
+
+struct PublishThread : public Client {
+ string destination;
+ string routingKey;
+
+ PublishThread() {};
+
+ PublishThread(string key, string dest=string()) {
+ destination=dest;
+ routingKey=key;
+ }
+
+ void run() { // Publisher
+ Completion completion;
+ 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 += string(reinterpret_cast<const char*>(session.getId().data()), session.getId().size());
+ 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);
+
+
+ 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(uint32_t),
+ reinterpret_cast<const char*>(&i), sizeof(uint32_t));
+ completion = session.messageTransfer(
+ arg::destination=destination,
+ arg::content=msg,
+ arg::confirmMode=opts.confirm);
+ if (opts.intervalPub) ::usleep(opts.intervalPub*1000);
+ }
+ if (opts.confirm) completion.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);
+ }
+ session.close();
+ }
+ catch (const std::exception& e) {
+ cout << "PublishThread exception: " << e.what() << endl;
+ exit(1);
+ }
+ }
+};
+
+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.queueBind(arg::queue=queue,
+ arg::exchange=ex,
+ arg::routingKey=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);
+ throw Exception(error.getData());
+ }
+ }
+
+ void run() { // Subscribe
+ try {
+ SubscriptionManager subs(session);
+ LocalQueue lq(AckPolicy(opts.ack));
+ subs.setConfirmMode(opts.ack > 0);
+ subs.setFlowControl(opts.subQuota, SubscriptionManager::UNLIMITED,
+ false);
+ subs.subscribe(lq, queue);
+ // Notify controller we are ready.
+ session.messageTransfer(arg::content=Message("ready", "sub_ready"));
+
+
+ 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.intervalSub) ::usleep(opts.intervalSub*1000);
+ // TODO aconway 2007-11-23: check message order for.
+ // multiple publishers. Need an acorray 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 uint32_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.ack !=0)
+ msg.acknowledge(); // Cumulative ack for final batch.
+ AbsTime end=now();
+
+ // Report to publisher.
+ Message result(lexical_cast<string>(opts.subQuota/secs(start,end)),
+ "sub_done");
+ session.messageTransfer(arg::content=result);
+ }
+ session.close();
+ }
+ catch (const std::exception& e) {
+ cout << "SubscribeThread exception: " << e.what() << endl;
+ exit(1);
+ }
+ }
+};
+
+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/qpid/cpp/src/tests/python_tests b/qpid/cpp/src/tests/python_tests
new file mode 100755
index 0000000000..f35cb16480
--- /dev/null
+++ b/qpid/cpp/src/tests/python_tests
@@ -0,0 +1,20 @@
+#!/bin/sh
+# Run the python tests.
+QPID_PORT=${QPID_PORT:-5672}
+PYTHON_TESTS=${PYTHON_TESTS:-$*}
+
+
+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 ../../../python ; then
+ cd ../../../python
+ run 0-10 cpp_failing_0-10.txt
+ test -z "$QPID_NO_PREVIEW" && run ../specs/amqp.0-10-preview.xml cpp_failing_0-10_preview.txt
+else
+ echo Warning: python tests not found.
+fi
+
diff --git a/qpid/cpp/src/tests/qpid_test_plugin.h b/qpid/cpp/src/tests/qpid_test_plugin.h
new file mode 100644
index 0000000000..b2f4a8ffed
--- /dev/null
+++ b/qpid/cpp/src/tests/qpid_test_plugin.h
@@ -0,0 +1,43 @@
+#ifndef _qpid_test_plugin_
+#define _qpid_test_plugin_
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/**
+ * Convenience to include cppunit headers needed by qpid test plugins and
+ * workaround for warning from superfluous main() declaration
+ * in cppunit/TestPlugIn.h
+ */
+
+#include <cppunit/TestCase.h>
+#include <cppunit/TextTestRunner.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/plugin/TestPlugIn.h>
+
+// Redefine CPPUNIT_PLUGIN_IMPLEMENT_MAIN to a dummy typedef to avoid warnings.
+//
+#if defined(CPPUNIT_HAVE_UNIX_DLL_LOADER) || defined(CPPUNIT_HAVE_UNIX_SHL_LOADER)
+#undef CPPUNIT_PLUGIN_IMPLEMENT_MAIN
+#define CPPUNIT_PLUGIN_IMPLEMENT_MAIN() typedef char __CppUnitPlugInImplementMainDummyTypeDef
+#endif
+
+#endif /*!_qpid_test_plugin_*/
diff --git a/qpid/cpp/src/tests/quick_perftest b/qpid/cpp/src/tests/quick_perftest
new file mode 100755
index 0000000000..676436fdc7
--- /dev/null
+++ b/qpid/cpp/src/tests/quick_perftest
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec `dirname $0`/run_test ./perftest --summary --count 100
diff --git a/qpid/cpp/src/tests/quick_topictest b/qpid/cpp/src/tests/quick_topictest
new file mode 100755
index 0000000000..b1e63b9350
--- /dev/null
+++ b/qpid/cpp/src/tests/quick_topictest
@@ -0,0 +1,9 @@
+#!/bin/sh
+# 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/qpid/cpp/src/tests/run-unit-tests b/qpid/cpp/src/tests/run-unit-tests
new file mode 100755
index 0000000000..464ce131f5
--- /dev/null
+++ b/qpid/cpp/src/tests/run-unit-tests
@@ -0,0 +1,28 @@
+#!/bin/sh
+#
+# 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/qpid/cpp/src/tests/run_federation_tests b/qpid/cpp/src/tests/run_federation_tests
new file mode 100755
index 0000000000..1f5917af0e
--- /dev/null
+++ b/qpid/cpp/src/tests/run_federation_tests
@@ -0,0 +1,24 @@
+#!/bin/sh
+# Run the federation tests.
+
+trap stop_brokers EXIT
+
+start_brokers() {
+ ../qpidd --daemon --port 0 --no-data-dir --auth no > qpidd.port
+ LOCAL_PORT=`cat qpidd.port`
+ ../qpidd --daemon --port 0 --no-data-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 ; then
+ start_brokers
+ echo "Running federation tests using brokers on ports $LOCAL_PORT $REMOTE_PORT"
+ export PYTHONPATH=../../../python
+ ./federation.py -v -s ../../../specs/amqp.0-10-preview.xml -b localhost:$LOCAL_PORT --remote-port $REMOTE_PORT || { echo "FAIL federation tests"; exit 1; }
+fi
+
diff --git a/qpid/cpp/src/tests/run_perftest b/qpid/cpp/src/tests/run_perftest
new file mode 100755
index 0000000000..c1e66294c1
--- /dev/null
+++ b/qpid/cpp/src/tests/run_perftest
@@ -0,0 +1,8 @@
+#!/bin/sh
+# 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/qpid/cpp/src/tests/run_test b/qpid/cpp/src/tests/run_test
new file mode 100755
index 0000000000..0f59509dab
--- /dev/null
+++ b/qpid/cpp/src/tests/run_test
@@ -0,0 +1,51 @@
+#!/bin/sh
+#
+# 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.
+#
+
+source `dirname $0`/vg_check
+
+
+# Export variables from makefile.
+export VALGRIND srcdir
+
+# Export QPID_PORT if qpidd.port exists.
+test -f qpidd.port && export QPID_PORT=`cat qpidd.port`
+
+# Avoid silly libtool error messages if these are not defined
+test -z "$LC_ALL" && export LC_ALL=
+test -z "$LC_CTYPE" && export LC_CTYPE=
+test -z "$LC_COLLATE" && export LC_COLLATE=
+test -z "$LC_MESSAGES" && export LC_MESSAGES=
+
+VG_LOG="$1.vglog"
+rm -f $VG_LOG
+
+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 --log-file-exactly=$VG_LOG --"
+ # Hide output unless there's an error.
+ libtool --mode=execute $VALGRIND "$@" 2>&1 || ERROR=$?
+ test -n "$VALGRIND" && vg_check
+else
+ # This is a non-libtool shell script, just execute it.
+ export VALGRIND srcdir
+ exec "$@"
+fi
+
+if test -z "$ERROR"; then
+ # Clean up logs if there was no error.
+ rm -f $VG_LOG
+ exit 0
+else
+ exit $ERROR
+fi
diff --git a/qpid/cpp/src/tests/shared_perftest b/qpid/cpp/src/tests/shared_perftest
new file mode 100755
index 0000000000..212ba22df4
--- /dev/null
+++ b/qpid/cpp/src/tests/shared_perftest
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec `dirname $0`/run_perftest 100000 --mode shared --npubs 16 --nsubs 16
diff --git a/qpid/cpp/src/tests/shlibtest.cpp b/qpid/cpp/src/tests/shlibtest.cpp
new file mode 100644
index 0000000000..80320ea7be
--- /dev/null
+++ b/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/qpid/cpp/src/tests/start_broker b/qpid/cpp/src/tests/start_broker
new file mode 100755
index 0000000000..7d5cb7d73d
--- /dev/null
+++ b/qpid/cpp/src/tests/start_broker
@@ -0,0 +1,4 @@
+#!/bin/sh
+rm -f qpidd.vglog qpidd.log
+test -n "$VALGRIND" && VALGRIND="$VALGRIND --log-file-exactly=qpidd.vglog --"
+exec libtool --mode=execute $VALGRIND ../qpidd --auth no --daemon --port 0 --log-output qpidd.log "$@" > qpidd.port
diff --git a/qpid/cpp/src/tests/start_cluster b/qpid/cpp/src/tests/start_cluster
new file mode 100755
index 0000000000..03fb671bdf
--- /dev/null
+++ b/qpid/cpp/src/tests/start_cluster
@@ -0,0 +1,19 @@
+#!/bin/sh
+# Start a cluster of brokers on local host.
+# Print the cluster's URL.
+#
+
+test -f cluster.ports && { echo "cluster.ports file already exists" ; exit 1; }
+test -z "$*" && { echo "Usage: $0 cluster-size [options]"; exit 1; }
+
+rm -f cluster*.log cluster.ports
+SIZE=$1
+shift
+OPTS=$*
+CLUSTER=`whoami` # Cluster name=user name, avoid clashes.
+for (( i=0; i<SIZE; ++i )); do
+ PORT=`../qpidd --load-module ../.libs/libqpidcluster.so -dp0 --log-output=cluster$i.log --cluster-name $CLUSTER $OPTS` || exit 1
+ echo $PORT >> cluster.ports
+done
+
+
diff --git a/qpid/cpp/src/tests/stop_broker b/qpid/cpp/src/tests/stop_broker
new file mode 100755
index 0000000000..e141ef9841
--- /dev/null
+++ b/qpid/cpp/src/tests/stop_broker
@@ -0,0 +1,20 @@
+#!/bin/sh
+# Stop the broker, check for errors.
+#
+export QPID_PORT=`cat qpidd.port`
+rm -f qpidd.port
+
+../qpidd --quit || ERROR=$?
+
+# Check qpidd.log.
+grep -a 'warning\|error\|critical' qpidd.log && {
+ echo "WARNING: Suspicious broker log entries in qpidd.log, above."
+}
+
+# Check valgrind log.
+if test -n "$VALGRIND"; then
+ source `dirname $0`/vg_check
+ vg_check qpidd.vglog
+fi
+
+exit $ERROR
diff --git a/qpid/cpp/src/tests/stop_cluster b/qpid/cpp/src/tests/stop_cluster
new file mode 100755
index 0000000000..6afcb527e5
--- /dev/null
+++ b/qpid/cpp/src/tests/stop_cluster
@@ -0,0 +1,14 @@
+#!/bin/sh
+# 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/qpid/cpp/src/tests/test_tools.h b/qpid/cpp/src/tests/test_tools.h
new file mode 100644
index 0000000000..c5451643be
--- /dev/null
+++ b/qpid/cpp/src/tests/test_tools.h
@@ -0,0 +1,78 @@
+#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 <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> */
+#define BOOST_CHECK_REGEX(re, text) \
+ BOOST_CHECK_PREDICATE(regexPredicate, (re)(text))
+
+/** 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())
+
+#endif /*!TEST_TOOLS_H*/
+
diff --git a/qpid/cpp/src/tests/topic_listener.cpp b/qpid/cpp/src/tests/topic_listener.cpp
new file mode 100644
index 0000000000..e5e7d24112
--- /dev/null
+++ b/qpid/cpp/src/tests/topic_listener.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.
+ *
+ */
+
+/**
+ * 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(Session& session, SubscriptionManager& mgr, const string& reponseQueue, bool tx);
+ virtual void received(Message& msg);
+};
+
+/**
+ * A utility class for managing the options passed in.
+ */
+struct Args : public qpid::TestOptions {
+ int ack;
+ bool transactional;
+ bool durable;
+ int prefetch;
+
+ 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)");
+ }
+};
+
+
+/**
+ * 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.trace);
+ args.open(connection);
+ Session session = connection.newSession(ASYNC);
+ if (args.transactional) {
+ session.txSelect();
+ }
+
+ //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.queueBind(arg::exchange="amq.topic", arg::queue=control, arg::routingKey="topic_control");
+
+ //set up listener
+ SubscriptionManager mgr(session);
+ Listener listener(session, mgr, "response", args.transactional);
+ if (args.prefetch) {
+ mgr.setAckPolicy(AckPolicy(args.ack ? args.ack : (args.prefetch / 2)));
+ mgr.setFlowControl(args.prefetch, SubscriptionManager::UNLIMITED, true);
+ } else {
+ mgr.setConfirmMode(false);
+ mgr.setFlowControl(SubscriptionManager::UNLIMITED, SubscriptionManager::UNLIMITED, false);
+ }
+ mgr.subscribe(listener, control);
+
+ 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(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;
+ }
+ FieldTable::ValuePtr type(message.getHeaders().get("TYPE"));
+
+ if(!!type && StringValue("TERMINATION_REQUEST") == *type){
+ shutdown();
+ }else if(!!type && StringValue("REPORT_REQUEST") == *type){
+ message.acknowledge();//acknowledge 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::content=msg);
+ if(transactional){
+ session.txCommit();
+ }
+}
+
diff --git a/qpid/cpp/src/tests/topic_perftest b/qpid/cpp/src/tests/topic_perftest
new file mode 100755
index 0000000000..5d317610f3
--- /dev/null
+++ b/qpid/cpp/src/tests/topic_perftest
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec `dirname $0`/run_perftest 10000 --mode topic --qt 16
diff --git a/qpid/cpp/src/tests/topic_publisher.cpp b/qpid/cpp/src/tests/topic_publisher.cpp
new file mode 100644
index 0000000000..2271849c35
--- /dev/null
+++ b/qpid/cpp/src/tests/topic_publisher.cpp
@@ -0,0 +1,206 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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/Session.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 {
+ Session& session;
+ SubscriptionManager mgr;
+ LocalQueue queue;
+ const string controlTopic;
+ const bool transactional;
+ const bool durable;
+
+ string generateData(int size);
+
+public:
+ Publisher(Session& 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;
+
+ 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");
+ }
+};
+
+int main(int argc, char** argv) {
+ try{
+ Args args;
+ args.parse(argc, argv);
+ if(args.help)
+ cout << args << endl;
+ else {
+ Connection connection(args.trace);
+ args.open(connection);
+ Session session = connection.newSession(ASYNC);
+ if (args.transactional) {
+ session.txSelect();
+ }
+
+
+ //declare queue (relying on default binding):
+ session.queueDeclare(arg::queue="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(Session& _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");
+ }
+ //send report request
+ Message reportRequest("", controlTopic);
+ reportRequest.getHeaders().setString("TYPE", "REPORT_REQUEST");
+ session.messageTransfer(arg::content=reportRequest, arg::destination="amq.topic");
+ if(transactional){
+ 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){
+ 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");
+ if(transactional){
+ session.txCommit();
+ }
+}
+
diff --git a/qpid/cpp/src/tests/topictest b/qpid/cpp/src/tests/topictest
new file mode 100755
index 0000000000..c36aa319ba
--- /dev/null
+++ b/qpid/cpp/src/tests/topictest
@@ -0,0 +1,40 @@
+#!/bin/bash
+# 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:" opt ; do
+ case $opt in
+ s) SUBSCRIBERS=$OPTARG ;;
+ m) MESSAGES=$OPTARG ;;
+ b) BATCHES=$OPTARG ;;
+ h) HOST=-h$OPTARG ;;
+ ?)
+ echo "Usage: %0 [-s <subscribers>] [-m <messages.] [-b <batches>]"
+ exit 1
+ ;;
+ esac
+done
+
+subscribe() {
+ echo Start subscriber $1
+ LOG="subscriber_$1.log"
+ ./topic_listener > $LOG 2>&1 && rm -f $LOG
+}
+
+publish() {
+ ./topic_publisher --messages $MESSAGES --batches $BATCHES --subscribers $SUBSCRIBERS $HOST
+}
+
+for ((i=$SUBSCRIBERS ; i--; )); do
+ subscribe $i &
+done
+# FIXME aconway 2007-03-27: Hack around startup race. Fix topic test.
+sleep 1
+publish 2>&1 || exit 1
diff --git a/qpid/cpp/src/tests/txtest.cpp b/qpid/cpp/src/tests/txtest.cpp
new file mode 100644
index 0000000000..4c5814986c
--- /dev/null
+++ b/qpid/cpp/src/tests/txtest.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 <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 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;
+
+ Args() : init(true), transfer(true), check(true),
+ size(256), durable(true), queues(2),
+ base("tx-test"), msgsPerTx(1), txCount(1), totalMsgCount(10)
+ {
+ 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'");
+ }
+};
+
+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;
+ Session session;
+
+ Client()
+ {
+ opts.open(connection);
+ session = connection.newSession(ASYNC);
+ }
+
+ ~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;
+
+ Transfer(const std::string& to, const std::string& from) : src(to), dest(from) {}
+
+ void run()
+ {
+ try {
+
+ session.txSelect();
+ SubscriptionManager subs(session);
+
+ LocalQueue lq(AckPolicy(0));//manual acking
+ subs.setFlowControl(opts.msgsPerTx, SubscriptionManager::UNLIMITED, true);
+ subs.subscribe(lq, src);
+
+ for (uint t = 0; t < opts.txCount; t++) {
+ Message in;
+ Message out("", dest);
+ 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);
+ }
+ in.acknowledge();
+ session.txCommit();
+ }
+ } catch(const std::exception& e) {
+ std::cout << "Transfer interrupted: " << e.what() << std::endl;
+ }
+ }
+};
+
+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).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);
+ }
+ }
+
+ 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();
+
+ 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();
+ }
+ }
+
+ void check()
+ {
+ SubscriptionManager subs(session);
+ subs.setFlowControl(SubscriptionManager::UNLIMITED, SubscriptionManager::UNLIMITED, false);
+ subs.setConfirmMode(false);
+
+ 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 flush
+ LocalQueue lq(AckPolicy(0));//manual acking
+ subs.subscribe(lq, *i, *i);
+ session.messageFlush(arg::destination=*i).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;
+ }
+ 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;
+ } 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;
+ }
+ }
+ }
+ }
+};
+
+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) controller.check();
+ return 0;
+ } catch(const std::exception& e) {
+ std::cout << e.what() << std::endl;
+ }
+ return 1;
+}
diff --git a/qpid/cpp/src/tests/unit_test.cpp b/qpid/cpp/src/tests/unit_test.cpp
new file mode 100644
index 0000000000..00c61242e4
--- /dev/null
+++ b/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/qpid/cpp/src/tests/unit_test.h b/qpid/cpp/src/tests/unit_test.h
new file mode 100644
index 0000000000..58ec20d26c
--- /dev/null
+++ b/qpid/cpp/src/tests/unit_test.h
@@ -0,0 +1,46 @@
+#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.
+
+#if (BOOST_VERSION < 103400)
+
+# include <boost/test/auto_unit_test.hpp>
+
+# define QPID_AUTO_TEST_SUITE(name) BOOST_AUTO_TEST_SUITE(name);
+# define QPID_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END();
+
+#else
+
+# define QPID_AUTO_TEST_SUITE(name) BOOST_AUTO_TEST_SUITE(name)
+# define QPID_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
+
+# include <boost/test/unit_test.hpp>
+#endif
+
+#endif /*!QPIPD_TEST_UNIT_TEST_H_*/
diff --git a/qpid/cpp/src/tests/vg_check b/qpid/cpp/src/tests/vg_check
new file mode 100644
index 0000000000..e9a691abe6
--- /dev/null
+++ b/qpid/cpp/src/tests/vg_check
@@ -0,0 +1,23 @@
+# Check for valgrind errors. Sourced by test scripts.
+
+vg_failed() {
+ 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_failed."
+ # 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_out; 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/qpid/cpp/versions b/qpid/cpp/versions
new file mode 100755
index 0000000000..2c82e3fd80
--- /dev/null
+++ b/qpid/cpp/versions
@@ -0,0 +1,12 @@
+#!/bin/sh
+# Utility to print out currently installed versions of qpid developer
+# dependencies. Assumes that some dependencies are installed with RPM.
+#
+
+for p in pkg-config doxygen help2man autoconf automake libtool ; do
+ echo `which $p` `$p --version | head -n1`
+done
+
+for r in apr boost boost-devel cppunit cppunit-devel graphviz; do
+ rpm -q $r
+done
diff --git a/qpid/cpp/xml/cluster.xml b/qpid/cpp/xml/cluster.xml
new file mode 100644
index 0000000000..d1e3293a3e
--- /dev/null
+++ b/qpid/cpp/xml/cluster.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+
+<amqp major="99" minor="0" port="5672">
+
+<class name = "cluster" index = "201">
+
+<doc>Qpid extension class to allow clustered brokers to communicate.</doc>
+
+<method name = "notify" index="10">
+ <doc>Notify the cluster of a members URL</doc>
+ <!-- No chassis element, this is handled by separte cluster code for now.-->
+ <field name="url" domain="longstr" />
+</method>
+
+</class>
+
+</amqp>
diff --git a/qpid/cpp/xml/extra.xml b/qpid/cpp/xml/extra.xml
new file mode 100644
index 0000000000..3e2f84e7bd
--- /dev/null
+++ b/qpid/cpp/xml/extra.xml
@@ -0,0 +1,938 @@
+<?xml version="1.0"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+
+<amqp major="99" minor="0" port="5672">
+
+ <domain name="mediumstr" type="mediumstr" label="string with 16bit size field" />
+
+ <domain name="sequence-set" type="sequence-set" label="ranged set representation">
+ <doc>
+ Set of pairs of RFC-1982 numbers representing a discontinuous range. Each pair represents a
+ closed interval within the list.
+
+ For example, the set (1,3), (6,6), (8,9) represents the sequence 1,2,3,6,8,9.
+ </doc>
+ </domain>
+
+ <domain name="xid010">
+ <struct size="short" pack="short">
+ <field name="format" domain="long" />
+ <field name="global-id" domain="shortstr" />
+ <field name="branch-id" domain="shortstr" />
+ </struct>
+ </domain>
+
+ <domain name="delivery-properties-010">
+ <struct size="long" pack="short" type="1025">
+ <field name="discard-unroutable" domain="bit" label="controls discard of unroutable messages"/>
+ <field name="immediate" domain="bit" label="Consider message unroutable if it cannot be
+ processed immediately"/>
+ <field name="redelivered" domain="bit" label="redelivery flag"/>
+ <field name="priority" domain="octet" label="message priority, 0 to 9"
+ required="true"/>
+ <field name="delivery-mode" domain="octet" label="message persistence requirement"
+ required="true"/>
+ <field name="ttl" domain="longlong" label="time to live in ms"/>
+ <field name="timestamp" domain="longlong" label="message timestamp"/>
+ <field name="expiration" domain="longlong" label="message expiration time"/>
+ <field name="exchange" domain="shortstr" label="originating exchange"/>
+ <field name="routing-key" domain="shortstr" label="message routing key"/>
+ <field name="resume-id" domain="mediumstr" label="global id for message transfer"/>
+ <field name="resume-ttl" domain="longlong" label="ttl in ms for interrupted message data"/>
+ </struct>
+ </domain>
+
+ <domain name="message-properties-010">
+ <struct size="long" pack="short" type="1027">
+ <field name="content-length" domain="longlong" label="length of the body segment in bytes"/>
+ <field name="message-id" domain="uuid" label="application message identifier"/>
+ <field name="correlation-id" domain="mediumstr" label="application correlation identifier"/>
+ <field name="reply-to" domain="reply-to" label="destination to reply to"/>
+ <field name="content-type" domain="shortstr" label="MIME content type"/>
+ <field name="content-encoding" domain="shortstr" label="MIME content encoding"/>
+ <field name="user-id" domain="mediumstr" label="creating user id"/>
+ <field name="app-id" domain="mediumstr" label="creating application id"/>
+ <field name="application-headers" domain="table" label="application specific headers table"/>
+ </struct>
+ </domain>
+
+<class name = "connection010" index = "1">
+
+<method name = "start" index="1">
+ <doc>new start method</doc>
+ <chassis name="client" implement="MUST" />
+
+ <response name="start-ok" />
+
+ <field name="server-properties" domain="table" label="server properties">
+ <doc>blah, blah</doc>
+ </field>
+
+ <field name="mechanisms" domain="array" label="available security mechanisms">
+ <doc>blah, blah</doc>
+ </field>
+
+ <field name="locales" domain="array" label="available message locales">
+ </field>
+
+</method>
+
+<method name = "start-ok" index="2">
+ <doc>new start-ok method</doc>
+ <chassis name="server" implement="MUST" />
+
+ <field name="client-properties" domain="table" label="server properties">
+ <doc>blah, blah</doc>
+ </field>
+
+ <field name="mechanism" domain="shortstr" label="chosen security mechanism">
+ <doc>blah, blah</doc>
+ </field>
+
+ <field name="response" domain="longstr" label="security response data">
+ <doc>blah blah</doc>
+ </field>
+
+ <field name="locale" domain="shortstr" label="chosen locale">
+ <doc>blah, blah</doc>
+ </field>
+
+</method>
+
+ <method name="secure" synchronous="1" index="3" label="security mechanism challenge">
+ <doc>
+ The SASL protocol works by exchanging challenges and responses until both peers have
+ received sufficient information to authenticate each other. This method challenges the
+ client to provide more information.
+ </doc>
+
+ <chassis name="client" implement="MUST" />
+
+ <response name="secure-ok" />
+
+ <field name="challenge" domain="longstr" label="security challenge data">
+ <doc>
+ Challenge information, a block of opaque binary data passed to the security mechanism.
+ </doc>
+ </field>
+ </method>
+
+ <!-- - Method: connection.secure-ok - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+ <method name="secure-ok" synchronous="1" index="4" label="security mechanism response">
+ <doc>
+ This method attempts to authenticate, passing a block of SASL data for the security
+ mechanism at the server side.
+ </doc>
+
+ <chassis name="server" implement="MUST" />
+
+ <field name="response" domain="longstr" label="security response data">
+ <doc>
+ A block of opaque data passed to the security mechanism. The contents of this data are
+ defined by the SASL security mechanism.
+ </doc>
+ <assert check="notnull" />
+ </field>
+ </method>
+
+ <method name="tune" synchronous="1" index="5" label="propose connection tuning parameters">
+ <doc>
+ This method proposes a set of connection configuration values to the client. The client can
+ accept and/or adjust these.
+ </doc>
+
+ <chassis name="client" implement="MUST" />
+
+ <response name="tune-ok" />
+
+ <field name="channel-max" domain="short" label="proposed maximum channels">
+ <doc>
+ The maximum total number of channels that the server allows per connection. Zero means
+ that the server does not impose a fixed limit, but the number of allowed channels may be
+ limited by available server resources.
+ </doc>
+ </field>
+
+ <field name="frame-max" domain="short" label="proposed maximum frame size">
+ <doc>
+ The largest frame size that the server proposes for the connection. The client can
+ negotiate a lower value. Zero means that the server does not impose any specific limit but
+ may reject very large frames if it cannot allocate resources for them.
+ </doc>
+
+ <rule name="minimum">
+ <doc>
+ Until the frame-max has been negotiated, both peers MUST accept frames of up to
+ frame-min-size octets large, and the minimum negotiated value for frame-max is also
+ frame-min-size.
+ </doc>
+ <doc type="scenario">
+ Client connects to server and sends a large properties field, creating a frame of
+ frame-min-size octets. The server must accept this frame.
+ </doc>
+ </rule>
+ </field>
+
+ <field name="heartbeat-min" domain="short" label="desired heartbeat delay"/>
+ <field name="heartbeat-max" domain="short" label="desired heartbeat delay"/>
+ </method>
+
+ <!-- - Method: connection.tune-ok - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+ <method name="tune-ok" synchronous="1" index="6"
+ label="negotiate connection tuning parameters">
+ <doc>
+ This method sends the client's connection tuning parameters to the server. Certain fields
+ are negotiated, others provide capability information.
+ </doc>
+
+ <chassis name="server" implement="MUST" />
+
+ <field name="channel-max" domain="short" label="negotiated maximum channels">
+ <doc>
+ The maximum total number of channels that the client will use per connection.
+ </doc>
+
+ <rule name="upper-limit">
+ <doc>
+ If the client specifies a channel max that is higher than the value provided by the
+ server, the server MUST close the connection without attempting a negotiated close. The
+ server may report the error in some fashion to assist implementors.
+ </doc>
+ </rule>
+
+ <assert check="notnull" />
+ <assert check="le" value="channel-max" />
+ </field>
+
+ <field name="frame-max" domain="short" label="negotiated maximum frame size">
+ <doc>
+ The largest frame size that the client and server will use for the connection. Zero means
+ that the client does not impose any specific limit but may reject very large frames if it
+ cannot allocate resources for them. Note that the frame-max limit applies principally to
+ content frames, where large contents can be broken into frames of arbitrary size.
+ </doc>
+
+ <rule name="minimum">
+ <doc>
+ Until the frame-max has been negotiated, both peers MUST accept frames of up to
+ frame-min-size octets large, and the minimum negotiated value for frame-max is also
+ frame-min-size.
+ </doc>
+ </rule>
+
+ <rule name="upper-limit">
+ <doc>
+ If the client specifies a frame max that is higher than the value provided by the
+ server, the server MUST close the connection without attempting a negotiated close. The
+ server may report the error in some fashion to assist implementors.
+ </doc>
+ </rule>
+ </field>
+
+ <field name="heartbeat" domain="short" label="desired heartbeat delay">
+ <doc>
+ The delay, in seconds, of the connection heartbeat that the client wants. Zero means the
+ client does not want a heartbeat.
+ </doc>
+ </field>
+ </method>
+
+ <method name="open" synchronous="1" index="7" label="open connection to virtual host">
+ <doc>
+ This method opens a connection to a virtual host, which is a collection of resources, and
+ acts to separate multiple application domains within a server. The server may apply
+ arbitrary limits per virtual host, such as the number of each type of entity that may be
+ used, per connection and/or in total.
+ </doc>
+
+ <chassis name="server" implement="MUST" />
+
+ <response name="open-ok" />
+ <response name="redirect" />
+
+ <field name="virtual-host" domain="path" label="virtual host name">
+ <!-- TODO 0.82 - the entire vhost model needs review. This concept was prompted by the HTTP
+ vhost concept but does not fit very well into AMQP. Currently we use the vhost as a
+ "cluster identifier" which is inaccurate usage. /PH 2006/07/19
+ -->
+ <doc>
+ The name of the virtual host to work with.
+ </doc>
+
+ <rule name="separation">
+ <doc>
+ If the server supports multiple virtual hosts, it MUST enforce a full separation of
+ exchanges, queues, and all associated entities per virtual host. An application,
+ connected to a specific virtual host, MUST NOT be able to access resources of another
+ virtual host.
+ </doc>
+ </rule>
+
+ <rule name="security">
+ <doc>
+ The server SHOULD verify that the client has permission to access the specified virtual
+ host.
+ </doc>
+ </rule>
+ <assert check="regexp" value="^[a-zA-Z0-9/-_]+$" />
+ </field>
+
+ <field name="capabilities" domain="array" label="required capabilities">
+ <doc>
+ The client can specify zero or more capability names, delimited by spaces. The server can
+ use this string to how to process the client's connection request.
+ </doc>
+ </field>
+
+ <field name="insist" domain="bit" label="insist on connecting to server">
+ <doc>
+ In a configuration with multiple collaborating servers, the server may respond to a
+ Connection.Open method with a Connection.Redirect. The insist option tells the server that
+ the client is insisting on a connection to the specified server.
+ </doc>
+ <rule name="behaviour">
+ <doc>
+ When the client uses the insist option, the server MUST NOT respond with a
+ Connection.Redirect method. If it cannot accept the client's connection request it
+ should respond by closing the connection with a suitable reply code.
+ </doc>
+ </rule>
+ </field>
+ </method>
+
+ <method name="open-ok" synchronous="1" index="8" label="signal that connection is ready">
+ <doc>
+ This method signals to the client that the connection is ready for use.
+ </doc>
+
+ <chassis name="client" implement="MUST" />
+
+ <field name="known-hosts" domain="array" />
+ </method>
+
+ <method name="redirect" synchronous="1" index="9" label="redirects client to other server">
+ <doc>
+ This method redirects the client to another server, based on the requested virtual host
+ and/or capabilities.
+ </doc>
+
+ <rule name="usage">
+ <doc>
+ When getting the Connection.Redirect method, the client SHOULD reconnect to the host
+ specified, and if that host is not present, to any of the hosts specified in the
+ known-hosts list.
+ </doc>
+ </rule>
+
+ <chassis name="client" implement="MUST" />
+
+ <field name="host" domain="shortstr" label="server to connect to">
+ <doc>
+ Specifies the server to connect to. This is an IP address or a DNS name, optionally
+ followed by a colon and a port number. If no port number is specified, the client should
+ use the default port number for the protocol.
+ </doc>
+ <assert check="notnull" />
+ </field>
+
+ <field name="known-hosts" domain="known-hosts" />
+ </method>
+
+<method name = "heartbeat" index="10">
+ <doc>new start-ok method</doc>
+ <chassis name="server" implement="MUST" />
+</method>
+
+ <!-- - Method: connection.close - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+ <method name="close" synchronous="1" index="11" label="request a connection close">
+ <doc>
+ This method indicates that the sender wants to close the connection. This may be due to
+ internal conditions (e.g. a forced shut-down) or due to an error handling a specific method,
+ i.e. an exception. When a close is due to an exception, the sender provides the class and
+ method id of the method which caused the exception.
+ </doc>
+ <!-- TODO: The connection close mechanism needs to be reviewed from the ODF documentation and
+ better expressed as rules here. /PH 2006/07/20
+ -->
+
+ <rule name="stability">
+ <doc>
+ After sending this method any received method except the Close-OK method MUST be
+ discarded.
+ </doc>
+ </rule>
+
+ <chassis name="client" implement="MUST" />
+ <chassis name="server" implement="MUST" />
+
+ <response name="close-ok" />
+
+ <field name="reply-code" domain="reply-code" />
+ <field name="reply-text" domain="reply-text" />
+
+ <field name="class-id" domain="class-id" label="failing method class">
+ <doc>
+ When the close is provoked by a method exception, this is the class of the method.
+ </doc>
+ </field>
+
+ <field name="method-id" domain="method-id" label="failing method ID">
+ <doc>
+ When the close is provoked by a method exception, this is the ID of the method.
+ </doc>
+ </field>
+ </method>
+
+ <!-- - Method: connection.close-ok - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+ <method name="close-ok" synchronous="1" index="12" label="confirm a connection close">
+ <doc>
+ This method confirms a Connection.Close method and tells the recipient that it is safe to
+ release resources for the connection and close the socket.
+ </doc>
+
+ <rule name="reporting">
+ <doc>
+ A peer that detects a socket closure without having received a Close-Ok handshake method
+ SHOULD log the error.
+ </doc>
+ </rule>
+
+ <chassis name="client" implement="MUST" />
+ <chassis name="server" implement="MUST" />
+ </method>
+
+
+</class>
+
+
+
+<class name = "session010" index = "2">
+
+<method name = "attach" index="1">
+
+ <doc>blah, blah</doc>
+ <chassis name="client" implement="MUST" />
+ <chassis name="server" implement="MUST" />
+
+ <response name="start-ok" />
+
+ <field name="name" domain="mediumstr" label="blah">
+ <doc>blah, blah</doc>
+ </field>
+
+ <field name="force" domain="bit" label="blah">
+ <doc>blah, blah</doc>
+ </field>
+
+</method>
+
+<method name = "attached" index="2">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <chassis name="client" implement="MUST" />
+
+ <field name="name" domain="mediumstr" label="blah">
+ <doc>blah, blah</doc>
+ </field>
+
+</method>
+
+<method name = "detach" index="3">
+
+ <doc>blah, blah</doc>
+ <chassis name="client" implement="MUST" />
+ <chassis name="server" implement="MUST" />
+
+ <response name="start-ok" />
+
+ <field name="name" domain="mediumstr" label="blah">
+ <doc>blah, blah</doc>
+ </field>
+
+</method>
+
+<method name = "detached" index="4">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <chassis name="client" implement="MUST" />
+
+ <field name="name" domain="mediumstr" label="blah">
+ <doc>blah, blah</doc>
+ </field>
+
+
+ <field name="detach-code" domain="octet" label="blah">
+ <doc>blah, blah</doc>
+ </field>
+
+</method>
+
+<method name = "request-timeout" index="5">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <chassis name="client" implement="MUST" />
+
+ <field name="timeout" domain="long" label="blah">
+ <doc>blah, blah</doc>
+ </field>
+</method>
+
+<method name = "timeout" index="6">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <chassis name="client" implement="MUST" />
+
+ <field name="timeout" domain="long" label="blah">
+ <doc>blah, blah</doc>
+ </field>
+</method>
+
+
+<method name = "command-point" index="7">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <chassis name="client" implement="MUST" />
+
+ <field name="command-id" domain="rfc1982-long" label="blah">
+ <doc>blah, blah</doc>
+ </field>
+
+
+ <field name="command-offset" domain="longlong" label="blah">
+ <doc>blah, blah</doc>
+ </field>
+</method>
+
+<method name = "expected" index="8">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <chassis name="client" implement="MUST" />
+
+ <field name="commands" domain="sequence-set" label="blah">
+ <doc>blah, blah</doc>
+ </field>
+
+ <field name="fragments" domain="array" label="blah">
+ <doc>blah, blah</doc>
+ </field>
+</method>
+
+<method name = "confirmed" index="9">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <chassis name="client" implement="MUST" />
+
+ <field name="commands" domain="sequence-set" label="blah">
+ <doc>blah, blah</doc>
+ </field>
+
+ <field name="fragments" domain="array" label="blah">
+ <doc>blah, blah</doc>
+ </field>
+</method>
+
+<method name = "completed" index="10">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <chassis name="client" implement="MUST" />
+
+ <field name="commands" domain="sequence-set" label="blah">
+ <doc>blah, blah</doc>
+ </field>
+
+ <field name="timely-reply" domain="bit" label="blah">
+ <doc>blah, blah</doc>
+ </field>
+</method>
+
+<method name = "known-completed" index="11">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <chassis name="client" implement="MUST" />
+
+ <field name="commands" domain="sequence-set" label="blah">
+ <doc>blah, blah</doc>
+ </field>
+</method>
+
+<method name = "flush" index="12">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <chassis name="client" implement="MUST" />
+
+ <field name="expected" domain="bit" label="blah">
+ <doc>blah, blah</doc>
+ </field>
+ <field name="confirmed" domain="bit" label="blah">
+ <doc>blah, blah</doc>
+ </field>
+ <field name="completed" domain="bit" label="blah">
+ <doc>blah, blah</doc>
+ </field>
+</method>
+
+<method name = "gap" index="13">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <chassis name="client" implement="MUST" />
+
+ <field name="commands" domain="sequence-set" label="blah">
+ <doc>blah, blah</doc>
+ </field>
+</method>
+
+</class>
+
+<class name="execution010" index="3">
+ <method name = "sync" index="1">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <chassis name="client" implement="MUST" />
+ </method>
+ <method name = "result" index="2">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <chassis name="client" implement="MUST" />
+ <field name="command-id" domain="command-id"/>
+ <field name="value" domain="long-struct"/>
+ </method>
+ <method name = "exception" index="3">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <chassis name="client" implement="MUST" />
+ <field name="error-code" domain="short"/>
+ <field name="command-id" domain="long"/>
+ <field name="class-code" domain="octet"/>
+ <field name="command-code" domain="octet"/>
+ <field name="field-index" domain="octet"/>
+ <field name="description" domain="mediumstr"/>
+ <field name="error-info" domain="table"/>
+ </method>
+</class>
+
+<class name="message010" index="4">
+ <doc>blah, blah</doc>
+ <method name = "transfer" index="1">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <chassis name="client" implement="MUST" />
+ <field name="destination" domain="shortstr"/>
+ <field name="accept-mode" domain="octet"/>
+ <field name="acquire-mode" domain="octet"/>
+ </method>
+ <method name = "accept" index="2">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <chassis name="client" implement="MUST" />
+ <field name="commands" domain="sequence-set"/>
+ </method>
+ <method name = "reject" index="3">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <chassis name="client" implement="MUST" />
+ <field name="commands" domain="sequence-set"/>
+ <field name="code" domain="short"/>
+ <field name="text" domain="shortstr"/>
+ </method>
+ <method name = "release" index="4">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <field name="commands" domain="sequence-set"/>
+ <field name="set-redelivered" domain="bit"/>
+ </method>
+ <method name = "acquire" index="5">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <field name="transfers" domain="sequence-set"/>
+ <result>
+ <struct size="long" type="4">
+ <field name="transfers" domain="sequence-set"/>
+ </struct>
+ </result>
+ </method>
+
+ <method name = "subscribe" index="7">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <field name="queue" domain="shortstr"/>
+ <field name="destination" domain="shortstr"/>
+ <field name="accept-mode" domain="octet"/>
+ <field name="acquire-mode" domain="octet"/>
+ <field name="exclusive" domain="bit"/>
+ <field name="resume-id" domain="mediumstr"/>
+ <field name="resume-ttl" domain="longlong"/>
+ <field name="arguments" domain="table"/>
+ </method>
+ <method name = "cancel" index="8">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <field name="destination" domain="shortstr"/>
+ </method>
+ <method name = "set-flow-mode" index="9">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <field name="destination" domain="shortstr"/>
+ <field name="flow-mode" domain="octet"/>
+ </method>
+ <method name = "flow" index="10">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <field name="destination" domain="shortstr"/>
+ <field name="unit" domain="octet"/>
+ <field name="value" domain="long"/>
+ </method>
+ <method name = "flush" index="11">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <field name="destination" domain="shortstr"/>
+ </method>
+ <method name = "stop" index="12">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <field name="destination" domain="shortstr"/>
+ </method>
+</class>
+
+<class name="tx010" index="5">
+ <doc>blah, blah</doc>
+ <method name = "select" index="1">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ </method>
+ <method name = "commit" index="2">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ </method>
+ <method name = "rollback" index="3">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ </method>
+</class>
+
+<class name="dtx010" index="6">
+ <doc>blah, blah</doc>
+ <method name = "select" index="1">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ </method>
+ <method name = "start" index="2">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <field name="xid" domain="xid010"/>
+ <field name="join" domain="bit"/>
+ <field name="resume" domain="bit"/>
+ <result>
+ <struct size="long" pack="short" type="1">
+ <field name="status" domain="short" />
+ </struct>
+ </result>
+ </method>
+ <method name = "end" index="3">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <field name="xid" domain="xid010"/>
+ <field name="fail" domain="bit"/>
+ <field name="suspend" domain="bit"/>
+ <result>
+ <struct size="long" pack="short" type="1">
+ <field name="status" domain="short" />
+ </struct>
+ </result>
+ </method>
+ <method name = "commit" index="4">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <field name="xid" domain="xid010"/>
+ <field name="one-phase" domain="bit"/>
+ <result>
+ <struct size="long" pack="short" type="1">
+ <field name="status" domain="short" />
+ </struct>
+ </result>
+ </method>
+ <method name = "forget" index="5">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <field name="xid" domain="xid010"/>
+ </method>
+ <method name = "get-timeout" index="6">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <field name="xid" domain="xid010"/>
+ <result>
+ <struct size="long" pack="short" type="2">
+ <field name="timeout" domain="long" />
+ </struct>
+ </result>
+ </method>
+ <method name = "prepare" index="7">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <field name="xid" domain="xid010"/>
+ <result>
+ <struct size="long" pack="short" type="1">
+ <field name="status" domain="short" />
+ </struct>
+ </result>
+ </method>
+ <method name = "recover" index="8">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <result>
+ <struct size="long" pack="short" type="3">
+ <field name="in-doubt" domain="array" />
+ </struct>
+ </result>
+ </method>
+ <method name = "rollback" index="9">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <field name="xid" domain="xid010"/>
+ <result>
+ <struct size="long" pack="short" type="1">
+ <field name="status" domain="short" />
+ </struct>
+ </result>
+ </method>
+ <method name = "set-timeout" index="10">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <field name="xid" domain="xid010"/>
+ <field name="timeout" domain="long"/>
+ </method>
+</class>
+
+<class name="exchange010" index="7">
+ <doc>blah, blah</doc>
+ <method name = "declare" index="1">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <field name="name" domain="shortstr"/>
+ <field name="type" domain="shortstr"/>
+ <field name="alternate-exchange" domain="shortstr"/>
+ <field name="passive" domain="bit"/>
+ <field name="durable" domain="bit"/>
+ <field name="auto-delete" domain="bit"/>
+ <field name="arguments" domain="table"/>
+ </method>
+ <method name = "delete" index="2">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <field name="name" domain="shortstr"/>
+ <field name="if-unused" domain="bit"/>
+ </method>
+ <method name = "query" index="3">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <field name="name" domain="shortstr"/>
+ <result>
+ <struct size="long" type="1">
+ <field name="type" domain="shortstr"/>
+ <field name="durable" domain="bit"/>
+ <field name="not-found" domain="bit"/>
+ <field name="arguments" domain="table"/>
+ </struct>
+ </result>
+ </method>
+ <method name = "bind" index="4">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <field name="queue" domain="shortstr"/>
+ <field name="exchange" domain="shortstr"/>
+ <field name="binding-key" domain="shortstr"/>
+ <field name="arguments" domain="table"/>
+ </method>
+ <method name = "unbind" index="5">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <field name="queue" domain="shortstr"/>
+ <field name="exchange" domain="shortstr"/>
+ <field name="binding-key" domain="shortstr"/>
+ </method>
+ <method name = "bound" index="6">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <field name="queue" domain="shortstr"/>
+ <field name="exchange" domain="shortstr"/>
+ <field name="binding-key" domain="shortstr"/>
+ <field name="arguments" domain="table"/>
+ <result>
+ <struct size="long" type="2">
+ <field name="exchange-not-found" domain="bit"/>
+ <field name="queue-not-found" domain="bit"/>
+ <field name="queue-not-matched" domain="bit"/>
+ <field name="key-not-matched" domain="bit"/>
+ <field name="arguments-not-matched" domain="bit"/>
+ </struct>
+ </result>
+ </method>
+</class>
+
+<class name="queue010" index="8">
+ <doc>blah, blah</doc>
+ <method name = "declare" index="1">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <field name="name" domain="shortstr"/>
+ <field name="alternate-exchange" domain="shortstr"/>
+ <field name="passive" domain="bit"/>
+ <field name="durable" domain="bit"/>
+ <field name="exclusive" domain="bit"/>
+ <field name="auto-delete" domain="bit"/>
+ <field name="arguments" domain="table"/>
+ </method>
+ <method name = "delete" index="2">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <field name="name" domain="shortstr"/>
+ <field name="if-unused" domain="bit"/>
+ <field name="if-empty" domain="bit"/>
+ </method>
+ <method name = "purge" index="3">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <field name="name" domain="shortstr"/>
+ </method>
+ <method name = "query" index="4">
+ <doc>blah, blah</doc>
+ <chassis name="server" implement="MUST" />
+ <field name="name" domain="shortstr"/>
+ <result>
+ <struct size="long" type="1">
+ <field name="name" domain="shortstr"/>
+ <field name="alternate-exchange" domain="shortstr"/>
+ <field name="passive" domain="bit"/>
+ <field name="durable" domain="bit"/>
+ <field name="auto-delete" domain="bit"/>
+ <field name="arguments" domain="table"/>
+ <field name="message-count" domain="long"/>
+ <field name="subscriber-count" domain="long"/>
+ </struct>
+ </result>
+ </method>
+</class>
+
+</amqp>