summaryrefslogtreecommitdiff
path: root/qpid/cpp/src/qpid/amqp
diff options
context:
space:
mode:
Diffstat (limited to 'qpid/cpp/src/qpid/amqp')
-rw-r--r--qpid/cpp/src/qpid/amqp/CharSequence.cpp2
-rw-r--r--qpid/cpp/src/qpid/amqp/Descriptor.cpp97
-rw-r--r--qpid/cpp/src/qpid/amqp/Descriptor.h2
-rw-r--r--qpid/cpp/src/qpid/amqp/Encoder.cpp37
-rw-r--r--qpid/cpp/src/qpid/amqp/Encoder.h25
-rw-r--r--qpid/cpp/src/qpid/amqp/descriptors.h5
6 files changed, 148 insertions, 20 deletions
diff --git a/qpid/cpp/src/qpid/amqp/CharSequence.cpp b/qpid/cpp/src/qpid/amqp/CharSequence.cpp
index 7e433bd26e..ad5b0ec84c 100644
--- a/qpid/cpp/src/qpid/amqp/CharSequence.cpp
+++ b/qpid/cpp/src/qpid/amqp/CharSequence.cpp
@@ -35,7 +35,7 @@ CharSequence::operator bool() const
}
std::string CharSequence::str() const
{
- return std::string(data, size);
+ return (data && size) ? std::string(data, size) : std::string();
}
CharSequence CharSequence::create()
diff --git a/qpid/cpp/src/qpid/amqp/Descriptor.cpp b/qpid/cpp/src/qpid/amqp/Descriptor.cpp
index 9e33294edd..43d388ee76 100644
--- a/qpid/cpp/src/qpid/amqp/Descriptor.cpp
+++ b/qpid/cpp/src/qpid/amqp/Descriptor.cpp
@@ -19,11 +19,17 @@
*
*/
#include "Descriptor.h"
+#include "descriptors.h"
+#include <qpid/framing/reply_exceptions.h>
+#include <map>
namespace qpid {
namespace amqp {
+
Descriptor::Descriptor(uint64_t code) : type(NUMERIC) { value.code = code; }
+
Descriptor::Descriptor(const CharSequence& symbol) : type(SYMBOLIC) { value.symbol = symbol; }
+
bool Descriptor::match(const std::string& symbol, uint64_t code) const
{
switch (type) {
@@ -58,20 +64,85 @@ Descriptor* Descriptor::nest(const Descriptor& d)
return nested.get();
}
-std::ostream& operator<<(std::ostream& os, const Descriptor& d)
-{
- switch (d.type) {
- case Descriptor::SYMBOLIC:
- if (d.value.symbol.data && d.value.symbol.size) os << std::string(d.value.symbol.data, d.value.symbol.size);
- else os << "null";
- break;
- case Descriptor::NUMERIC:
- os << "0x" << std::hex << d.value.code;
- break;
+namespace {
+
+class DescriptorMap {
+ typedef std::map<uint64_t, std::string> SymbolMap;
+ typedef std::map<std::string, uint64_t> CodeMap;
+
+ SymbolMap symbols;
+ CodeMap codes;
+
+ public:
+ DescriptorMap() {
+ symbols[message::HEADER_CODE] = message::HEADER_SYMBOL;
+ symbols[message::DELIVERY_ANNOTATIONS_CODE] = message::DELIVERY_ANNOTATIONS_SYMBOL;
+ symbols[message::MESSAGE_ANNOTATIONS_CODE] = message::MESSAGE_ANNOTATIONS_SYMBOL;
+ symbols[message::PROPERTIES_CODE] = message::PROPERTIES_SYMBOL;
+ symbols[message::APPLICATION_PROPERTIES_CODE] = message::APPLICATION_PROPERTIES_SYMBOL;
+ symbols[message::DATA_CODE] = message::DATA_SYMBOL;
+ symbols[message::AMQP_SEQUENCE_CODE] = message::AMQP_SEQUENCE_SYMBOL;
+ symbols[message::AMQP_VALUE_CODE] = message::AMQP_VALUE_SYMBOL;
+ symbols[message::FOOTER_CODE] = message::FOOTER_SYMBOL;
+ symbols[message::ACCEPTED_CODE] = message::ACCEPTED_SYMBOL;
+ symbols[sasl::SASL_MECHANISMS_CODE] = sasl::SASL_MECHANISMS_SYMBOL;
+ symbols[sasl::SASL_INIT_CODE] = sasl::SASL_INIT_SYMBOL;
+ symbols[sasl::SASL_CHALLENGE_CODE] = sasl::SASL_CHALLENGE_SYMBOL;
+ symbols[sasl::SASL_RESPONSE_CODE] = sasl::SASL_RESPONSE_SYMBOL;
+ symbols[sasl::SASL_OUTCOME_CODE] = sasl::SASL_OUTCOME_SYMBOL;
+ symbols[filters::LEGACY_DIRECT_FILTER_CODE] = filters::LEGACY_DIRECT_FILTER_SYMBOL;
+ symbols[filters::LEGACY_TOPIC_FILTER_CODE] = filters::LEGACY_TOPIC_FILTER_SYMBOL;
+ symbols[filters::LEGACY_HEADERS_FILTER_CODE] = filters::LEGACY_HEADERS_FILTER_SYMBOL;
+ symbols[filters::SELECTOR_FILTER_CODE] = filters::SELECTOR_FILTER_SYMBOL;
+ symbols[filters::XQUERY_FILTER_CODE] = filters::XQUERY_FILTER_SYMBOL;
+ symbols[lifetime_policy::DELETE_ON_CLOSE_CODE] = lifetime_policy::DELETE_ON_CLOSE_SYMBOL;
+ symbols[lifetime_policy::DELETE_ON_NO_LINKS_CODE] = lifetime_policy::DELETE_ON_NO_LINKS_SYMBOL;
+ symbols[lifetime_policy::DELETE_ON_NO_MESSAGES_CODE] = lifetime_policy::DELETE_ON_NO_MESSAGES_SYMBOL;
+ symbols[lifetime_policy::DELETE_ON_NO_LINKS_OR_MESSAGES_CODE] = lifetime_policy::DELETE_ON_NO_LINKS_OR_MESSAGES_SYMBOL;
+ symbols[transaction::DECLARE_CODE] = transaction::DECLARE_SYMBOL;
+ symbols[transaction::DISCHARGE_CODE] = transaction::DISCHARGE_SYMBOL;
+ symbols[transaction::DECLARED_CODE] = transaction::DECLARED_SYMBOL;
+ symbols[transaction::TRANSACTIONAL_STATE_CODE] = transaction::TRANSACTIONAL_STATE_SYMBOL;
+ symbols[0] = "unknown-descriptor";
+
+ for (SymbolMap::const_iterator i = symbols.begin(); i != symbols.end(); ++i)
+ codes[i->second] = i->first;
+ }
+
+ std::string operator[](uint64_t code) const {
+ SymbolMap::const_iterator i = symbols.find(code);
+ return (i == symbols.end()) ? "unknown-descriptor" : i->second;
}
- if (d.nested.get()) {
- os << " ->(" << *d.nested << ")";
+
+ uint64_t operator[](const std::string& symbol) const {
+ CodeMap::const_iterator i = codes.find(symbol);
+ return (i == codes.end()) ? 0 : i->second;
+ }
+};
+
+DescriptorMap DESCRIPTOR_MAP;
+}
+
+std::string Descriptor::symbol() const {
+ switch (type) {
+ case Descriptor::NUMERIC: return DESCRIPTOR_MAP[value.code];
+ case Descriptor::SYMBOLIC: return value.symbol.str();
+ }
+ assert(0);
+ return std::string();
+}
+
+uint64_t Descriptor::code() const {
+ switch (type) {
+ case Descriptor::NUMERIC: return value.code;
+ case Descriptor::SYMBOLIC: return DESCRIPTOR_MAP[value.symbol.str()];
}
- return os;
+ assert(0);
+ return 0;
}
+
+std::ostream& operator<<(std::ostream& os, const Descriptor& d) {
+ return os << d.symbol() << "(" << "0x" << std::hex << d.code() << ")";
+}
+
}} // namespace qpid::amqp
diff --git a/qpid/cpp/src/qpid/amqp/Descriptor.h b/qpid/cpp/src/qpid/amqp/Descriptor.h
index 6b0cb80e87..3726114769 100644
--- a/qpid/cpp/src/qpid/amqp/Descriptor.h
+++ b/qpid/cpp/src/qpid/amqp/Descriptor.h
@@ -49,6 +49,8 @@ struct Descriptor
QPID_COMMON_EXTERN bool match(const std::string&, uint64_t) const;
QPID_COMMON_EXTERN size_t getSize() const;
QPID_COMMON_EXTERN Descriptor* nest(const Descriptor& d);
+ QPID_COMMON_EXTERN std::string symbol() const;
+ QPID_COMMON_EXTERN uint64_t code() const;
};
QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream& os, const Descriptor& d);
diff --git a/qpid/cpp/src/qpid/amqp/Encoder.cpp b/qpid/cpp/src/qpid/amqp/Encoder.cpp
index 0760fc166d..86b59fb1a2 100644
--- a/qpid/cpp/src/qpid/amqp/Encoder.cpp
+++ b/qpid/cpp/src/qpid/amqp/Encoder.cpp
@@ -31,10 +31,17 @@
#include <string.h>
using namespace qpid::types::encodings;
+using qpid::types::Variant;
namespace qpid {
namespace amqp {
+Encoder::Overflow::Overflow() : Exception("Buffer overflow in encoder!") {}
+
+Encoder::Encoder(char* d, size_t s) : data(d), size(s), position(0), grow(false) {}
+
+Encoder::Encoder() : data(0), size(0), position(0), grow(true) {}
+
namespace {
template <typename T> size_t encode(char* data, T i);
template <> size_t encode<uint8_t>(char* data, uint8_t i)
@@ -406,6 +413,18 @@ void Encoder::writeList(const std::list<qpid::types::Variant>& value, const Desc
void Encoder::writeValue(const qpid::types::Variant& value, const Descriptor* d)
{
+ if (d) {
+ writeDescriptor(*d); // Write this descriptor before any in the value.
+ d = 0;
+ }
+ // Write any descriptors attached to the value.
+ const Variant::List& descriptors = value.getDescriptors();
+ for (Variant::List::const_iterator i = descriptors.begin(); i != descriptors.end(); ++i) {
+ if (i->getType() == types::VAR_STRING)
+ writeDescriptor(Descriptor(CharSequence::create(i->asString())));
+ else
+ writeDescriptor(Descriptor(i->asUint64()));
+ }
switch (value.getType()) {
case qpid::types::VAR_VOID:
writeNull(d);
@@ -477,18 +496,28 @@ void Encoder::writeDescriptor(const Descriptor& d)
break;
}
}
+
void Encoder::check(size_t s)
{
if (position + s > size) {
- QPID_LOG(notice, "Buffer overflow for write of size " << s << " to buffer of size " << size << " at position " << position);
- assert(false);
- throw qpid::Exception("Buffer overflow in encoder!");
+ if (grow) {
+ buffer.resize(buffer.size() + s);
+ data = const_cast<char*>(buffer.data());
+ size = buffer.size();
+ }
+ else {
+ QPID_LOG(notice, "Buffer overflow for write of size " << s
+ << " to buffer of size " << size << " at position " << position);
+ assert(false);
+ throw Overflow();
+ }
}
}
-Encoder::Encoder(char* d, size_t s) : data(d), size(s), position(0) {}
+
size_t Encoder::getPosition() { return position; }
size_t Encoder::getSize() const { return size; }
char* Encoder::getData() { return data + position; }
+std::string Encoder::getBuffer() { return buffer; }
void Encoder::resetPosition(size_t p) { assert(p <= size); position = p; }
}} // namespace qpid::amqp
diff --git a/qpid/cpp/src/qpid/amqp/Encoder.h b/qpid/cpp/src/qpid/amqp/Encoder.h
index 4f7c1d1489..8729f29b94 100644
--- a/qpid/cpp/src/qpid/amqp/Encoder.h
+++ b/qpid/cpp/src/qpid/amqp/Encoder.h
@@ -23,6 +23,7 @@
*/
#include "qpid/sys/IntegerTypes.h"
#include "qpid/amqp/Constructor.h"
+#include "qpid/Exception.h"
#include <list>
#include <map>
#include <stddef.h>
@@ -43,6 +44,18 @@ struct Descriptor;
class Encoder
{
public:
+ struct Overflow : public Exception { Overflow(); };
+
+ /** Create an encoder that writes into the buffer at data up to size bytes.
+ * Write operations throw Overflow if encoding exceeds size bytes.
+ */
+ QPID_COMMON_EXTERN Encoder(char* data, size_t size);
+
+ /** Create an encoder that manages its own buffer. Buffer grows to accomodate
+ * all encoded data. Call getBuffer() to get the buffer.
+ */
+ QPID_COMMON_EXTERN Encoder();
+
void writeCode(uint8_t);
void write(bool);
@@ -100,19 +113,27 @@ class Encoder
QPID_COMMON_EXTERN void writeList(const std::list<qpid::types::Variant>& value, const Descriptor* d=0, bool large=true);
void writeDescriptor(const Descriptor&);
- QPID_COMMON_EXTERN Encoder(char* data, size_t size);
QPID_COMMON_EXTERN size_t getPosition();
void resetPosition(size_t p);
char* skip(size_t);
void writeBytes(const char* bytes, size_t count);
virtual ~Encoder() {}
+
+ /** Return the total size of the buffer. */
size_t getSize() const;
- protected:
+
+ /** Return the growable buffer. */
+ std::string getBuffer();
+
+ /** Return the unused portion of the buffer. */
char* getData();
+
private:
char* data;
size_t size;
size_t position;
+ bool grow;
+ std::string buffer;
void write(const CharSequence& v, std::pair<uint8_t, uint8_t> codes, const Descriptor* d);
void write(const std::string& v, std::pair<uint8_t, uint8_t> codes, const Descriptor* d);
diff --git a/qpid/cpp/src/qpid/amqp/descriptors.h b/qpid/cpp/src/qpid/amqp/descriptors.h
index a9ee12644a..29c626edc2 100644
--- a/qpid/cpp/src/qpid/amqp/descriptors.h
+++ b/qpid/cpp/src/qpid/amqp/descriptors.h
@@ -26,6 +26,9 @@
namespace qpid {
namespace amqp {
+// NOTE: If you add descriptor symbols and codes here, you must also update the DescriptorMap
+// constructor in Descriptor.cpp.
+
namespace message {
const std::string HEADER_SYMBOL("amqp:header:list");
const std::string PROPERTIES_SYMBOL("amqp:properties:list");
@@ -36,6 +39,7 @@ const std::string AMQP_SEQUENCE_SYMBOL("amqp:amqp-sequence:list");
const std::string AMQP_VALUE_SYMBOL("amqp:amqp-value:*");
const std::string DATA_SYMBOL("amqp:data:binary");
const std::string FOOTER_SYMBOL("amqp:footer:map");
+const std::string ACCEPTED_SYMBOL("amqp:accepted:list");
const uint64_t HEADER_CODE(0x70);
const uint64_t DELIVERY_ANNOTATIONS_CODE(0x71);
@@ -46,6 +50,7 @@ const uint64_t DATA_CODE(0x75);
const uint64_t AMQP_SEQUENCE_CODE(0x76);
const uint64_t AMQP_VALUE_CODE(0x77);
const uint64_t FOOTER_CODE(0x78);
+const uint64_t ACCEPTED_CODE(0x24);
const Descriptor HEADER(HEADER_CODE);
const Descriptor DELIVERY_ANNOTATIONS(DELIVERY_ANNOTATIONS_CODE);