Fixed a bug where a frame could be sent exceeding the maximum frame size (resulting in protocol errors) and added some optimizations

This commit is contained in:
Martijn Otto 2015-04-30 10:59:03 +02:00
parent b9caf0199d
commit 45deeaa754
9 changed files with 117 additions and 80 deletions

View File

@ -13,6 +13,7 @@
#include <string> #include <string>
#include <memory> #include <memory>
#include <map> #include <map>
#include <unordered_map>
#include <queue> #include <queue>
#include <set> #include <set>
#include <limits> #include <limits>

View File

@ -53,9 +53,9 @@ protected:
/** /**
* All channels that are active * All channels that are active
* @var map * @var std::unordered_map<uint16_t, std::shared_ptr<ChannelImpl>>
*/ */
std::map<uint16_t, std::shared_ptr<ChannelImpl>> _channels; std::unordered_map<uint16_t, std::shared_ptr<ChannelImpl>> _channels;
/** /**
* The last unused channel ID * The last unused channel ID

View File

@ -217,6 +217,23 @@ public:
void setTimestamp (uint64_t value) { _timestamp = value; _bools2.set(6,true); } void setTimestamp (uint64_t value) { _timestamp = value; _bools2.set(6,true); }
void setMessageID (const std::string &value) { _messageID = value; _bools2.set(7,true); } void setMessageID (const std::string &value) { _messageID = value; _bools2.set(7,true); }
/**
* Set the various supported fields using r-value references
*
* @param value moveable value
*/
void setExpiration (std::string &&value) { _expiration = std::move(value); _bools1.set(0,true); }
void setReplyTo (std::string &&value) { _replyTo = std::move(value); _bools1.set(1,true); }
void setCorrelationID (std::string &&value) { _correlationID = std::move(value); _bools1.set(2,true); }
void setHeaders (Table &&value) { _headers = std::move(value); _bools1.set(5,true); }
void setContentEncoding (std::string &&value) { _contentEncoding = std::move(value); _bools1.set(6,true); }
void setContentType (std::string &&value) { _contentType = std::move(value); _bools1.set(7,true); }
void setClusterID (std::string &&value) { _clusterID = std::move(value); _bools2.set(2,true); }
void setAppID (std::string &&value) { _appID = std::move(value); _bools2.set(3,true); }
void setUserID (std::string &&value) { _userID = std::move(value); _bools2.set(4,true); }
void setTypeName (std::string &&value) { _typeName = std::move(value); _bools2.set(5,true); }
void setMessageID (std::string &&value) { _messageID = std::move(value); _bools2.set(7,true); }
/** /**
* Retrieve the fields * Retrieve the fields
* @return string * @return string

View File

@ -21,9 +21,9 @@ class OutBuffer
private: private:
/** /**
* Pointer to the beginning of the buffer * Pointer to the beginning of the buffer
* @var char* * @var std::unique_ptr<char[]>
*/ */
char *_buffer; std::unique_ptr<char[]> _buffer;
/** /**
* Pointer to the buffer to be filled * Pointer to the buffer to be filled
@ -49,56 +49,47 @@ public:
* Constructor * Constructor
* @param capacity * @param capacity
*/ */
OutBuffer(uint32_t capacity) OutBuffer(uint32_t capacity) :
{ _buffer(new char[capacity]),
// initialize members _current(_buffer.get()),
_size = 0; _size(0),
_capacity = capacity; _capacity(capacity)
_buffer = _current = new char[capacity]; {}
}
/** /**
* Copy constructor * Copy constructor
* @param that * @param that
*/ */
OutBuffer(const OutBuffer &that) OutBuffer(const OutBuffer &that) :
_buffer(new char[that._capacity]),
_current(_buffer.get() + that._size),
_size(that._size),
_capacity(that._capacity)
{ {
// initialize members
_size = that._size;
_capacity = that._capacity;
_buffer = new char[_capacity];
_current = _buffer + _size;
// copy memory // copy memory
memcpy(_buffer, that._buffer, _size); memcpy(_buffer.get(), that._buffer.get(), _size);
} }
/** /**
* Move constructor * Move constructor
* @param that * @param that
*/ */
OutBuffer(OutBuffer &&that) OutBuffer(OutBuffer &&that) :
_buffer(std::move(that._buffer)),
_current(that._current),
_size(that._size),
_capacity(that._capacity)
{ {
// copy all members
_size = that._size;
_capacity = that._capacity;
_buffer = that._buffer;
_current = that._current;
// reset the other object // reset the other object
that._size = 0; that._size = 0;
that._capacity = 0; that._capacity = 0;
that._buffer = nullptr;
that._current = nullptr; that._current = nullptr;
} }
/** /**
* Destructor * Destructor
*/ */
virtual ~OutBuffer() virtual ~OutBuffer() {}
{
if (_buffer) delete[] _buffer;
}
/** /**
* Get access to the internal buffer * Get access to the internal buffer
@ -106,7 +97,7 @@ public:
*/ */
const char *data() const const char *data() const
{ {
return _buffer; return _buffer.get();
} }
/** /**

View File

@ -34,7 +34,14 @@ public:
* *
* @param value string value * @param value string value
*/ */
StringField(std::string value) : _data(value) {} StringField(const std::string &value) : _data(value) {}
/**
* Construct based on a std::string
*
* @param value string value
*/
StringField(std::string &&value) : _data(std::move(value)) {}
/** /**
* Construct based on received data * Construct based on received data
@ -69,7 +76,7 @@ public:
* *
* @param value new value * @param value new value
*/ */
StringField& operator=(const std::string& value) StringField& operator=(const std::string &value)
{ {
// overwrite data // overwrite data
_data = value; _data = value;
@ -78,6 +85,20 @@ public:
return *this; return *this;
} }
/**
* Assign a new value
*
* @param value new value
*/
StringField& operator=(std::string &&value)
{
// overwrite data
_data = std::move(value);
// allow chaining
return *this;
}
/** /**
* Get the size this field will take when * Get the size this field will take when
* encoded in the AMQP wire-frame format * encoded in the AMQP wire-frame format

View File

@ -287,6 +287,10 @@ bool ConnectionImpl::send(const Frame &frame)
// some frames can be sent _after_ the close() function was called // some frames can be sent _after_ the close() function was called
if (_closed && !frame.partOfShutdown()) return false; if (_closed && !frame.partOfShutdown()) return false;
// if the frame is bigger than we allow on the connection
// it is impossible to send out this frame successfully
if (frame.totalSize() > _maxFrame) return false;
// we need an output buffer // we need an output buffer
OutBuffer buffer(frame.buffer()); OutBuffer buffer(frame.buffer());

View File

@ -18,6 +18,7 @@
#include <ostream> #include <ostream>
#include <math.h> #include <math.h>
#include <map> #include <map>
#include <unordered_map>
#include <vector> #include <vector>
#include <queue> #include <queue>

View File

@ -43,8 +43,10 @@ Table::Table(const Table &table)
// loop through the table records // loop through the table records
for (auto iter = table._fields.begin(); iter != table._fields.end(); iter++) for (auto iter = table._fields.begin(); iter != table._fields.end(); iter++)
{ {
// add the field // since a map is always ordered, we know that each element will
_fields[iter->first] = std::shared_ptr<Field>(iter->second->clone()); // be inserted at the end of the new map, so we can simply use
// emplace_hint and hint at insertion at the end of the map
_fields.emplace_hint(_fields.end(), std::make_pair(iter->first, iter->second->clone()));
} }
} }