1296 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1296 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
 * Copyright (c) 2018 MariaDB Corporation Ab
 | 
						|
 *
 | 
						|
 * Use of this software is governed by the Business Source License included
 | 
						|
 * in the LICENSE.TXT file and at www.mariadb.com/bsl11.
 | 
						|
 *
 | 
						|
 * Change Date: 2025-01-18
 | 
						|
 *
 | 
						|
 * On the date above, in accordance with the Business Source License, use
 | 
						|
 * of this software will be governed by version 2 or later of the General
 | 
						|
 * Public License.
 | 
						|
 */
 | 
						|
#pragma once
 | 
						|
 | 
						|
#include <maxscale/ccdefs.hh>
 | 
						|
#include <algorithm>
 | 
						|
#include <iterator>
 | 
						|
#include <memory>
 | 
						|
#include <stdint.h>
 | 
						|
#include <string.h>
 | 
						|
#include <vector>
 | 
						|
#include <maxbase/assert.h>
 | 
						|
#include <maxscale/hint.h>
 | 
						|
 | 
						|
class SERVER;
 | 
						|
 | 
						|
namespace maxscale
 | 
						|
{
 | 
						|
class Buffer;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Buffer properties - used to store properties related to the buffer
 | 
						|
 * contents. This may be added at any point during the processing of the
 | 
						|
 * data, especially in the protocol stage of the processing.
 | 
						|
 */
 | 
						|
struct BUF_PROPERTY
 | 
						|
{
 | 
						|
    char*         name;
 | 
						|
    char*         value;
 | 
						|
    BUF_PROPERTY* next;
 | 
						|
};
 | 
						|
 | 
						|
enum gwbuf_type_t
 | 
						|
{
 | 
						|
    GWBUF_TYPE_UNDEFINED      = 0,
 | 
						|
    GWBUF_TYPE_HTTP           = (1 << 0),
 | 
						|
    GWBUF_TYPE_IGNORABLE      = (1 << 1),
 | 
						|
    GWBUF_TYPE_COLLECT_RESULT = (1 << 2),
 | 
						|
    GWBUF_TYPE_RESULT         = (1 << 3),
 | 
						|
    GWBUF_TYPE_REPLY_OK       = (1 << 4),
 | 
						|
    GWBUF_TYPE_REPLAYED       = (1 << 5),
 | 
						|
    GWBUF_TYPE_TRACK_STATE    = (1 << 6),
 | 
						|
};
 | 
						|
 | 
						|
#define GWBUF_IS_TYPE_UNDEFINED(b)     ((b)->gwbuf_type == 0)
 | 
						|
#define GWBUF_IS_IGNORABLE(b)          ((b)->gwbuf_type & GWBUF_TYPE_IGNORABLE)
 | 
						|
#define GWBUF_IS_COLLECTED_RESULT(b)   ((b)->gwbuf_type & GWBUF_TYPE_RESULT)
 | 
						|
#define GWBUF_SHOULD_COLLECT_RESULT(b) ((b)->gwbuf_type & GWBUF_TYPE_COLLECT_RESULT)
 | 
						|
#define GWBUF_IS_REPLY_OK(b)           ((b)->gwbuf_type & GWBUF_TYPE_REPLY_OK)
 | 
						|
 | 
						|
// True if the query is not initiated by the client but an internal replaying mechanism
 | 
						|
#define GWBUF_IS_REPLAYED(b) ((b)->gwbuf_type & GWBUF_TYPE_REPLAYED)
 | 
						|
 | 
						|
// Track session state change response
 | 
						|
#define GWBUF_SHOULD_TRACK_STATE(b) ((b)->gwbuf_type & GWBUF_TYPE_TRACK_STATE)
 | 
						|
 | 
						|
enum  gwbuf_info_t
 | 
						|
{
 | 
						|
    GWBUF_INFO_NONE   = 0x0,
 | 
						|
    GWBUF_INFO_PARSED = 0x1
 | 
						|
};
 | 
						|
 | 
						|
#define GWBUF_IS_PARSED(b) (b->sbuf->info & GWBUF_INFO_PARSED)
 | 
						|
 | 
						|
/**
 | 
						|
 * A structure for cleaning up memory allocations of structures which are
 | 
						|
 * referred to by GWBUF and deallocated in gwbuf_free but GWBUF doesn't
 | 
						|
 * know what they are.
 | 
						|
 * All functions on the list are executed before freeing memory of GWBUF struct.
 | 
						|
 */
 | 
						|
enum bufobj_id_t
 | 
						|
{
 | 
						|
    GWBUF_PARSING_INFO
 | 
						|
};
 | 
						|
 | 
						|
struct buffer_object_t
 | 
						|
{
 | 
						|
    bufobj_id_t      bo_id;
 | 
						|
    void*            bo_data;
 | 
						|
    void             (* bo_donefun_fp)(void*);
 | 
						|
    buffer_object_t* bo_next;
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * A structure to encapsulate the data in a form that the data itself can be
 | 
						|
 * shared between multiple GWBUF's without the need to make multiple copies
 | 
						|
 * but still maintain separate data pointers.
 | 
						|
 */
 | 
						|
struct SHARED_BUF
 | 
						|
{
 | 
						|
    buffer_object_t* bufobj;    /*< List of objects referred to by GWBUF */
 | 
						|
    int32_t          refcount;  /*< Reference count on the buffer */
 | 
						|
    uint32_t         info;      /*< Info bits */
 | 
						|
    unsigned char    data[1];   /*< Actual memory that was allocated */
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * The buffer structure used by the descriptor control blocks.
 | 
						|
 *
 | 
						|
 * Linked lists of buffers are created as data is read from a descriptor
 | 
						|
 * or written to a descriptor. The use of linked lists of buffers with
 | 
						|
 * flexible data pointers is designed to minimise the need for data to
 | 
						|
 * be copied within the gateway.
 | 
						|
 */
 | 
						|
struct GWBUF
 | 
						|
{
 | 
						|
    GWBUF*        next;         /*< Next buffer in a linked chain of buffers */
 | 
						|
    GWBUF*        tail;         /*< Last buffer in a linked chain of buffers */
 | 
						|
    void*         start;        /*< Start of the valid data */
 | 
						|
    void*         end;          /*< First byte after the valid data */
 | 
						|
    SHARED_BUF*   sbuf;         /*< The shared buffer with the real data */
 | 
						|
    HINT*         hint;         /*< Hint data for this buffer */
 | 
						|
    BUF_PROPERTY* properties;   /*< Buffer properties */
 | 
						|
    SERVER*       server;       /*< The target server where the buffer is executed */
 | 
						|
    uint32_t      gwbuf_type;   /*< buffer's data type information */
 | 
						|
#ifdef SS_DEBUG
 | 
						|
    int owner;      /*< Owner of the thread, only for debugging */
 | 
						|
#endif
 | 
						|
};
 | 
						|
 | 
						|
/*<
 | 
						|
 * Macros to access the data in the buffers
 | 
						|
 */
 | 
						|
/*< First valid, unconsumed byte in the buffer */
 | 
						|
inline uint8_t* gwbuf_link_data(GWBUF* b)
 | 
						|
{
 | 
						|
    return static_cast<uint8_t*>(b->start);
 | 
						|
}
 | 
						|
 | 
						|
inline const uint8_t* gwbuf_link_data(const GWBUF* b)
 | 
						|
{
 | 
						|
    return static_cast<uint8_t*>(b->start);
 | 
						|
}
 | 
						|
 | 
						|
#define GWBUF_DATA(b) gwbuf_link_data(b)
 | 
						|
 | 
						|
/*< Number of bytes in the individual buffer */
 | 
						|
inline size_t gwbuf_link_length(const GWBUF* b)
 | 
						|
{
 | 
						|
    return (size_t)((char*)b->end - (char*)b->start);
 | 
						|
}
 | 
						|
 | 
						|
#define GWBUF_LENGTH(b) gwbuf_link_length(b)
 | 
						|
 | 
						|
/*< Check whether the buffer is contiguous*/
 | 
						|
inline bool gwbuf_is_contiguous(const GWBUF* b)
 | 
						|
{
 | 
						|
    mxb_assert(b);
 | 
						|
    return b->next == nullptr;
 | 
						|
}
 | 
						|
 | 
						|
#define GWBUF_IS_CONTIGUOUS(b) gwbuf_is_contiguous(b)
 | 
						|
 | 
						|
/*< True if all bytes in the buffer have been consumed */
 | 
						|
inline bool gwbuf_link_empty(const GWBUF* b)
 | 
						|
{
 | 
						|
    return (char*)b->start >= (char*)b->end;
 | 
						|
}
 | 
						|
 | 
						|
#define GWBUF_EMPTY(b) gwbuf_link_empty(b)
 | 
						|
 | 
						|
/*< Consume a number of bytes in the buffer */
 | 
						|
inline void gwbuf_link_consume(GWBUF* b, unsigned int bytes)
 | 
						|
{
 | 
						|
    b->start = bytes > ((char*)b->end - (char*)b->start) ? b->end : (void*)((char*)b->start + bytes);
 | 
						|
}
 | 
						|
 | 
						|
#define GWBUF_CONSUME(b, bytes) gwbuf_link_consume(b, bytes)
 | 
						|
 | 
						|
inline void gwbuf_link_rtrim(GWBUF* b, unsigned int bytes)
 | 
						|
{
 | 
						|
    b->end = bytes > ((char*)b->end - (char*)b->start) ? b->start : (void*)((char*)b->end - bytes);
 | 
						|
}
 | 
						|
 | 
						|
#define GWBUF_RTRIM(b, bytes) gwbuf_link_rtrim(b, bytes)
 | 
						|
 | 
						|
inline uint32_t gwbuf_type(const GWBUF* b)
 | 
						|
{
 | 
						|
    return b->gwbuf_type;
 | 
						|
}
 | 
						|
#define GWBUF_TYPE(b) gwbuf_type(b)
 | 
						|
 | 
						|
/*<
 | 
						|
 * Function prototypes for the API to maniplate the buffers
 | 
						|
 */
 | 
						|
 | 
						|
/**
 | 
						|
 * Allocate a new gateway buffer of specified size.
 | 
						|
 *
 | 
						|
 * @param size  The size in bytes of the data area required
 | 
						|
 *
 | 
						|
 * @return Pointer to the buffer structure or NULL if memory could not
 | 
						|
 *         be allocated.
 | 
						|
 */
 | 
						|
extern GWBUF* gwbuf_alloc(unsigned int size);
 | 
						|
 | 
						|
/**
 | 
						|
 * Allocate a new gateway buffer structure of specified size and load with data.
 | 
						|
 *
 | 
						|
 * @param size  The size in bytes of the data area required
 | 
						|
 * @param data  Pointer to the data (size bytes) to be loaded
 | 
						|
 *
 | 
						|
 * @return Pointer to the buffer structure or NULL if memory could not
 | 
						|
 *         be allocated.
 | 
						|
 */
 | 
						|
extern GWBUF* gwbuf_alloc_and_load(unsigned int size, const void* data);
 | 
						|
 | 
						|
/**
 | 
						|
 * Free a chain of gateway buffers
 | 
						|
 *
 | 
						|
 * @param buf  The head of the list of buffers to free, can be NULL.
 | 
						|
 */
 | 
						|
extern void gwbuf_free(GWBUF* buf);
 | 
						|
 | 
						|
/**
 | 
						|
 * Clone a GWBUF. Note that if the GWBUF is actually a list of
 | 
						|
 * GWBUFs, then every GWBUF in the list will be cloned. Note that but
 | 
						|
 * for the GWBUF structure itself, the data is shared.
 | 
						|
 *
 | 
						|
 * @param buf  The GWBUF to be cloned.
 | 
						|
 *
 | 
						|
 * @return The cloned GWBUF, or NULL if any part of @buf could not be cloned.
 | 
						|
 */
 | 
						|
extern GWBUF* gwbuf_clone(GWBUF* buf);
 | 
						|
 | 
						|
/**
 | 
						|
 * @brief Deep clone a GWBUF
 | 
						|
 *
 | 
						|
 * Clone the data inside a GWBUF into a new buffer. The created buffer has its
 | 
						|
 * own internal buffer and any modifications to the deep cloned buffer will not
 | 
						|
 * reflect on the original one. Any buffer objects attached to the original buffer
 | 
						|
 * will not be copied. Only the buffer type of the original buffer will be copied
 | 
						|
 * over to the cloned buffer.
 | 
						|
 *
 | 
						|
 * @param buf Buffer to clone
 | 
						|
 *
 | 
						|
 * @return Deep copy of @c buf or NULL on error
 | 
						|
 */
 | 
						|
extern GWBUF* gwbuf_deep_clone(const GWBUF* buf);
 | 
						|
 | 
						|
/**
 | 
						|
 * Compare two GWBUFs. Two GWBUFs are considered identical if their
 | 
						|
 * content is identical, irrespective of whether one is segmented and
 | 
						|
 * the other is not.
 | 
						|
 *
 | 
						|
 * @param lhs  One GWBUF
 | 
						|
 * @param rhs  Another GWBUF
 | 
						|
 *
 | 
						|
 * @return  0 if the content is identical,
 | 
						|
 *         -1 if @c lhs is less than @c rhs, and
 | 
						|
 *          1 if @c lhs is more than @c rhs.
 | 
						|
 *
 | 
						|
 * @attention A shorter @c GWBUF less than a longer one. Otherwise the
 | 
						|
 *            sign of the return value is determined by the sign of the
 | 
						|
 *            difference between the first pair of bytes (interpreted as
 | 
						|
 *            unsigned char) that differ in lhs and rhs.
 | 
						|
 */
 | 
						|
extern int gwbuf_compare(const GWBUF* lhs, const GWBUF* rhs);
 | 
						|
 | 
						|
/**
 | 
						|
 * Append a buffer onto a linked list of buffer structures.
 | 
						|
 *
 | 
						|
 * @param head  The current head of the linked list or NULL.
 | 
						|
 * @param tail  Another buffer to make the tail of the linked list, must not be NULL
 | 
						|
 *
 | 
						|
 * @return The new head of the linked list
 | 
						|
 */
 | 
						|
extern GWBUF* gwbuf_append(GWBUF* head, GWBUF* tail);
 | 
						|
 | 
						|
/**
 | 
						|
 * @brief Consume data from buffer chain
 | 
						|
 *
 | 
						|
 * Data is consumed from @p head until either @p length bytes have been
 | 
						|
 * processed or @p head is empty. If @p head points to a chain of buffers,
 | 
						|
 * those buffers are counted as a part of @p head and will also be consumed if
 | 
						|
 * @p length exceeds the size of the first buffer.
 | 
						|
 *
 | 
						|
 * @param head    The head of the linked list
 | 
						|
 * @param length  Number of bytes to consume
 | 
						|
 *
 | 
						|
 * @return The head of the linked list or NULL if everything was consumed
 | 
						|
 */
 | 
						|
extern GWBUF* gwbuf_consume(GWBUF* head, unsigned int length);
 | 
						|
 | 
						|
/**
 | 
						|
 * Trim bytes from the end of a GWBUF structure that may be the first
 | 
						|
 * in a list. If the buffer has n_bytes or less then it will be freed and
 | 
						|
 * the next buffer in the list will be returned, or if none, NULL.
 | 
						|
 *
 | 
						|
 * @param head     The buffer to trim
 | 
						|
 * @param n_bytes  The number of bytes to trim off
 | 
						|
 *
 | 
						|
 * @return The buffer chain or NULL if buffer chain now empty
 | 
						|
 */
 | 
						|
extern GWBUF* gwbuf_rtrim(GWBUF* head, unsigned int length);
 | 
						|
 | 
						|
/**
 | 
						|
 * Return the number of bytes of data in the linked list.
 | 
						|
 *
 | 
						|
 * @param head  The current head of the linked list
 | 
						|
 *
 | 
						|
 * @return The number of bytes of data in the linked list
 | 
						|
 */
 | 
						|
extern unsigned int gwbuf_length(const GWBUF* head);
 | 
						|
 | 
						|
/**
 | 
						|
 * Return the number of individual buffers in the linked list.
 | 
						|
 *
 | 
						|
 * Currently not used, provided mainly for use during debugging sessions.
 | 
						|
 *
 | 
						|
 * @param head  The current head of the linked list
 | 
						|
 *
 | 
						|
 * @return The number of bytes of data in the linked list
 | 
						|
 */
 | 
						|
extern int gwbuf_count(const GWBUF* head);
 | 
						|
 | 
						|
/**
 | 
						|
 * @brief Copy bytes from a buffer
 | 
						|
 *
 | 
						|
 * Copy bytes from a chain of buffers. Supports copying data from buffers where
 | 
						|
 * the data is spread across multiple buffers.
 | 
						|
 *
 | 
						|
 * @param buffer  Buffer to copy from
 | 
						|
 * @param offset  Offset into the buffer
 | 
						|
 * @param bytes   Number of bytes to copy
 | 
						|
 * @param dest    Destination where the bytes are copied
 | 
						|
 *
 | 
						|
 * @return Number of bytes copied.
 | 
						|
 */
 | 
						|
extern size_t gwbuf_copy_data(const GWBUF* buffer, size_t offset, size_t bytes, uint8_t* dest);
 | 
						|
 | 
						|
/**
 | 
						|
 * @brief Split a buffer in two
 | 
						|
 *
 | 
						|
 * The returned value will be @c length bytes long. If the length of @c buf
 | 
						|
 * exceeds @c length, the remaining buffers are stored in @buf.
 | 
						|
 *
 | 
						|
 * @param buf Buffer chain to split
 | 
						|
 * @param length Number of bytes that the returned buffer should contain
 | 
						|
 *
 | 
						|
 * @return Head of the buffer chain.
 | 
						|
 */
 | 
						|
extern GWBUF* gwbuf_split(GWBUF** buf, size_t length);
 | 
						|
 | 
						|
/**
 | 
						|
 * Set given type to all buffers on the list.
 | 
						|
 * *
 | 
						|
 * @param buf   The shared buffer
 | 
						|
 * @param type  Type to be added, mask of @c gwbuf_type_t values.
 | 
						|
 */
 | 
						|
extern void gwbuf_set_type(GWBUF* head, uint32_t type);
 | 
						|
 | 
						|
/**
 | 
						|
 * Add a property to a buffer.
 | 
						|
 *
 | 
						|
 * @param buf    The buffer to add the property to
 | 
						|
 * @param name   The property name
 | 
						|
 * @param value  The property value
 | 
						|
 *
 | 
						|
 * @return True on success, false otherwise.
 | 
						|
 */
 | 
						|
extern bool gwbuf_add_property(GWBUF* buf, const char* name, const char* value);
 | 
						|
 | 
						|
/**
 | 
						|
 * Return the value of a buffer property
 | 
						|
 *
 | 
						|
 * @param buf   The buffer itself
 | 
						|
 * @param name  The name of the property to return
 | 
						|
 *
 | 
						|
 * @return The property value or NULL if the property was not found.
 | 
						|
 */
 | 
						|
extern char* gwbuf_get_property(GWBUF* buf, const char* name);
 | 
						|
 | 
						|
/**
 | 
						|
 * Convert a chain of GWBUF structures into a single GWBUF structure
 | 
						|
 *
 | 
						|
 * @param orig  The chain to convert, must not be used after the function call
 | 
						|
 *
 | 
						|
 * @return A contiguous version of @c buf.
 | 
						|
 *
 | 
						|
 * @attention Never returns NULL, memory allocation failures abort the process
 | 
						|
 */
 | 
						|
extern GWBUF* gwbuf_make_contiguous(GWBUF* buf);
 | 
						|
 | 
						|
/**
 | 
						|
 * Add a buffer object to GWBUF buffer.
 | 
						|
 *
 | 
						|
 * @param buf         GWBUF where object is added
 | 
						|
 * @param id          Type identifier for object
 | 
						|
 * @param data        Object data
 | 
						|
 * @param donefun_fp  Clean-up function to be executed before buffer is freed.
 | 
						|
 */
 | 
						|
void gwbuf_add_buffer_object(GWBUF* buf,
 | 
						|
                             bufobj_id_t id,
 | 
						|
                             void* data,
 | 
						|
                             void (* donefun_fp)(void*));
 | 
						|
 | 
						|
/**
 | 
						|
 * Search buffer object which matches with the id.
 | 
						|
 *
 | 
						|
 * @param buf  GWBUF to be searched
 | 
						|
 * @param id   Identifier for the object
 | 
						|
 *
 | 
						|
 * @return Searched buffer object or NULL if not found
 | 
						|
 */
 | 
						|
void* gwbuf_get_buffer_object_data(GWBUF* buf, bufobj_id_t id);
 | 
						|
#if defined (BUFFER_TRACE)
 | 
						|
extern void dprintAllBuffers(void* pdcb);
 | 
						|
#endif
 | 
						|
 | 
						|
/**
 | 
						|
 * Debug function for dumping buffer contents to log
 | 
						|
 *
 | 
						|
 * @see mxs::Buffer::hexdump
 | 
						|
 *
 | 
						|
 * @param buffer    Buffer to dump
 | 
						|
 * @param log_level Log priority where the message is written
 | 
						|
 */
 | 
						|
void gwbuf_hexdump(GWBUF* buffer, int log_level = LOG_INFO);
 | 
						|
 | 
						|
/**
 | 
						|
 * Debug function for pretty-printing buffer contents to log
 | 
						|
 *
 | 
						|
 * @see mxs::Buffer::hexdump_pretty
 | 
						|
 *
 | 
						|
 * @param buffer    Buffer to dump
 | 
						|
 * @param log_level Log priority where the message is written
 | 
						|
 */
 | 
						|
void gwbuf_hexdump_pretty(GWBUF* buffer, int log_level = LOG_INFO);
 | 
						|
 | 
						|
/**
 | 
						|
 * Return pointer of the byte at offset from start of chained buffer
 | 
						|
 * Warning: It not guaranteed to point to a contiguous segment of memory,
 | 
						|
 * it is only safe to modify the first byte this pointer point to.
 | 
						|
 *
 | 
						|
 * @param buffer  one or more chained buffer
 | 
						|
 * @param offset  Offset into the buffer
 | 
						|
 * @return  if total buffer length is bigger than offset then return
 | 
						|
 *      the offset byte pointer, otherwise return null
 | 
						|
 */
 | 
						|
extern uint8_t* gwbuf_byte_pointer(GWBUF* buffer, size_t offset);
 | 
						|
 | 
						|
namespace std
 | 
						|
{
 | 
						|
 | 
						|
template<>
 | 
						|
struct default_delete<GWBUF>
 | 
						|
{
 | 
						|
    void operator()(GWBUF* pBuffer)
 | 
						|
    {
 | 
						|
        gwbuf_free(pBuffer);
 | 
						|
    }
 | 
						|
};
 | 
						|
}
 | 
						|
 | 
						|
namespace maxscale
 | 
						|
{
 | 
						|
 | 
						|
/**
 | 
						|
 * @class Buffer
 | 
						|
 *
 | 
						|
 * @c Buffer is a simple wrapper around @ GWBUF that is more convenient to
 | 
						|
 * use in a C++ context.
 | 
						|
 *
 | 
						|
 * As @c Buffer is a handle class, it should be created on the stack or as a
 | 
						|
 * member of an enclosing class, *never* dynamically.
 | 
						|
 *
 | 
						|
 * @c Buffer exposed _forward_ iterators to the underlying buffer that can
 | 
						|
 * be used in conjunction with standard C++ algorithms and functions.
 | 
						|
 */
 | 
						|
class Buffer
 | 
						|
{
 | 
						|
public:
 | 
						|
    // buf_type      : The type of the buffer, either "GWBUF*" or "const GWBUF*"
 | 
						|
    // pointer_type  : The type of a pointer to an element, either "uint8_t*" or "const uint8_t*".
 | 
						|
    // reference_type: The type of a reference to an element, either "uint8_t&" or "const uint8_t&".
 | 
						|
    template<class buf_type, class pointer_type, class reference_type>
 | 
						|
    class iterator_base : public std::iterator<
 | 
						|
                            std::forward_iterator_tag   // The type of the iterator
 | 
						|
                            , uint8_t                   // The type of the elems
 | 
						|
                            , std::ptrdiff_t            // Difference between two its
 | 
						|
                            , pointer_type              // The type of pointer to an elem
 | 
						|
                            , reference_type>           // The reference type of an elem
 | 
						|
    {
 | 
						|
    public:
 | 
						|
        /**
 | 
						|
         * Returns address of the internal pointer to a GWBUF.
 | 
						|
         *
 | 
						|
         * @attention This is provided as a backdoor for situations where it is
 | 
						|
         *            unavoidable to access the interal pointer directly. It should
 | 
						|
         *            carefully be assessed whether it actually can be avoided.
 | 
						|
         *
 | 
						|
         * @return Pointer to pointer to GWBUF.
 | 
						|
         */
 | 
						|
        pointer_type* address_of()
 | 
						|
        {
 | 
						|
            return &m_i;
 | 
						|
        }
 | 
						|
 | 
						|
        /**
 | 
						|
         * Advance the iterator
 | 
						|
         *
 | 
						|
         * This provides similar behavior to random access iterators with operator+= but does it in
 | 
						|
         * non-constant time.
 | 
						|
         *
 | 
						|
         * @param i Number of steps to advance the iterator
 | 
						|
         */
 | 
						|
        void advance(int i)
 | 
						|
        {
 | 
						|
            mxb_assert(m_i != m_end);
 | 
						|
            mxb_assert(i >= 0);
 | 
						|
 | 
						|
            while (m_i && m_i + i >= m_end)
 | 
						|
            {
 | 
						|
                i -= m_end - m_i;
 | 
						|
                m_pBuffer = m_pBuffer->next;
 | 
						|
 | 
						|
                if (m_pBuffer)
 | 
						|
                {
 | 
						|
                    m_i = GWBUF_DATA(m_pBuffer);
 | 
						|
                    m_end = m_i + GWBUF_LENGTH(m_pBuffer);
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    m_i = NULL;
 | 
						|
                    m_end = NULL;
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            if (m_i)
 | 
						|
            {
 | 
						|
                m_i += i;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
    protected:
 | 
						|
        iterator_base(buf_type pBuffer = NULL)
 | 
						|
            : m_pBuffer(pBuffer)
 | 
						|
            , m_i(m_pBuffer ? GWBUF_DATA(m_pBuffer) : NULL)
 | 
						|
            , m_end(m_pBuffer ? (m_i + GWBUF_LENGTH(m_pBuffer)) : NULL)
 | 
						|
        {
 | 
						|
        }
 | 
						|
 | 
						|
        void advance()
 | 
						|
        {
 | 
						|
            mxb_assert(m_i != m_end);
 | 
						|
 | 
						|
            ++m_i;
 | 
						|
 | 
						|
            if (m_i == m_end)
 | 
						|
            {
 | 
						|
                m_pBuffer = m_pBuffer->next;
 | 
						|
 | 
						|
                if (m_pBuffer)
 | 
						|
                {
 | 
						|
                    m_i = GWBUF_DATA(m_pBuffer);
 | 
						|
                    m_end = m_i + GWBUF_LENGTH(m_pBuffer);
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    m_i = NULL;
 | 
						|
                    m_end = NULL;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        bool eq(const iterator_base& rhs) const
 | 
						|
        {
 | 
						|
            return m_i == rhs.m_i;
 | 
						|
        }
 | 
						|
 | 
						|
        bool neq(const iterator_base& rhs) const
 | 
						|
        {
 | 
						|
            return !eq(rhs);
 | 
						|
        }
 | 
						|
 | 
						|
    protected:
 | 
						|
        buf_type     m_pBuffer;
 | 
						|
        pointer_type m_i;
 | 
						|
        pointer_type m_end;
 | 
						|
    };
 | 
						|
 | 
						|
    class const_iterator;
 | 
						|
 | 
						|
    // Buffer type, type of pointer to element and type of reference to element.
 | 
						|
    typedef iterator_base<GWBUF*, uint8_t*, uint8_t&> iterator_base_typedef;
 | 
						|
 | 
						|
    /**
 | 
						|
     * A forward iterator to Buffer.
 | 
						|
     */
 | 
						|
    class iterator : public iterator_base_typedef
 | 
						|
    {
 | 
						|
        friend class const_iterator;
 | 
						|
 | 
						|
    public:
 | 
						|
        explicit iterator(GWBUF* pBuffer = NULL)
 | 
						|
            : iterator_base_typedef(pBuffer)
 | 
						|
        {
 | 
						|
        }
 | 
						|
 | 
						|
        iterator& operator++()
 | 
						|
        {
 | 
						|
            advance();
 | 
						|
            return *this;
 | 
						|
        }
 | 
						|
 | 
						|
        iterator operator++(int)
 | 
						|
        {
 | 
						|
            iterator rv(*this);
 | 
						|
            ++(*this);
 | 
						|
            return rv;
 | 
						|
        }
 | 
						|
 | 
						|
        bool operator==(const iterator& rhs) const
 | 
						|
        {
 | 
						|
            return eq(rhs);
 | 
						|
        }
 | 
						|
 | 
						|
        bool operator!=(const iterator& rhs) const
 | 
						|
        {
 | 
						|
            return neq(rhs);
 | 
						|
        }
 | 
						|
 | 
						|
        reference operator*()
 | 
						|
        {
 | 
						|
            mxb_assert(m_i);
 | 
						|
            return *m_i;
 | 
						|
        }
 | 
						|
    };
 | 
						|
 | 
						|
    // Buffer type, type of pointer to element and type of reference to element.
 | 
						|
    typedef iterator_base<const GWBUF*, const uint8_t*, const uint8_t&> const_iterator_base_typedef;
 | 
						|
 | 
						|
    /**
 | 
						|
     * A const forward iterator to Buffer.
 | 
						|
     */
 | 
						|
    class const_iterator : public const_iterator_base_typedef
 | 
						|
    {
 | 
						|
    public:
 | 
						|
        explicit const_iterator(const GWBUF* pBuffer = NULL)
 | 
						|
            : const_iterator_base_typedef(pBuffer)
 | 
						|
        {
 | 
						|
        }
 | 
						|
 | 
						|
        const_iterator(const Buffer::iterator& rhs)
 | 
						|
            : const_iterator_base_typedef(rhs.m_pBuffer)
 | 
						|
        {
 | 
						|
            m_i = rhs.m_i;
 | 
						|
            m_end = rhs.m_end;
 | 
						|
        }
 | 
						|
 | 
						|
        const_iterator& operator++()
 | 
						|
        {
 | 
						|
            advance();
 | 
						|
            return *this;
 | 
						|
        }
 | 
						|
 | 
						|
        const_iterator operator++(int)
 | 
						|
        {
 | 
						|
            const_iterator rv(*this);
 | 
						|
            ++(*this);
 | 
						|
            return rv;
 | 
						|
        }
 | 
						|
 | 
						|
        bool operator==(const const_iterator& rhs) const
 | 
						|
        {
 | 
						|
            return eq(rhs);
 | 
						|
        }
 | 
						|
 | 
						|
        bool operator!=(const const_iterator& rhs) const
 | 
						|
        {
 | 
						|
            return neq(rhs);
 | 
						|
        }
 | 
						|
 | 
						|
        reference operator*() const
 | 
						|
        {
 | 
						|
            mxb_assert(m_i);
 | 
						|
            return *m_i;
 | 
						|
        }
 | 
						|
    };
 | 
						|
 | 
						|
    /**
 | 
						|
     * Creates an empty buffer.
 | 
						|
     */
 | 
						|
    Buffer()
 | 
						|
        : m_pBuffer(NULL)
 | 
						|
    {
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Copy constructor.
 | 
						|
     *
 | 
						|
     * @param rhs  The @c Buffer to copy.
 | 
						|
     *
 | 
						|
     * @throws @c std::bad_alloc if the underlying @c GWBUF cannot be cloned.
 | 
						|
     *
 | 
						|
     */
 | 
						|
    Buffer(const Buffer& rhs)
 | 
						|
    {
 | 
						|
        if (rhs.m_pBuffer)
 | 
						|
        {
 | 
						|
            m_pBuffer = gwbuf_clone(rhs.m_pBuffer);
 | 
						|
 | 
						|
            if (!m_pBuffer)
 | 
						|
            {
 | 
						|
                mxb_assert(!true);
 | 
						|
                throw std::bad_alloc();
 | 
						|
            }
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            m_pBuffer = NULL;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
#if __cplusplus >= 201103
 | 
						|
    /**
 | 
						|
     * Move constructor.
 | 
						|
     *
 | 
						|
     * @param rhs  The @c Buffer to be moved.
 | 
						|
     */
 | 
						|
    Buffer(Buffer&& rhs)
 | 
						|
        : m_pBuffer(NULL)
 | 
						|
    {
 | 
						|
        swap(rhs);
 | 
						|
    }
 | 
						|
#endif
 | 
						|
 | 
						|
    /**
 | 
						|
     * Creates a @Buffer from a @ GWBUF
 | 
						|
     *
 | 
						|
     * @param pBuffer  The buffer to create the @c Buffer from.
 | 
						|
     *
 | 
						|
     * @attention  The ownership of @c pBuffer is transferred to the
 | 
						|
     *             @c Buffer being created.
 | 
						|
     */
 | 
						|
    Buffer(GWBUF* pBuffer)
 | 
						|
        : m_pBuffer(pBuffer)
 | 
						|
    {
 | 
						|
        mxb_assert(pBuffer);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Creates a buffer of specified size.
 | 
						|
     *
 | 
						|
     * @param size  The size of the buffer.
 | 
						|
     *
 | 
						|
     * @attention  @c std::bad_alloc is thrown if the allocation fails.
 | 
						|
     */
 | 
						|
    Buffer(size_t size)
 | 
						|
        : m_pBuffer(gwbuf_alloc(size))
 | 
						|
    {
 | 
						|
        if (!m_pBuffer)
 | 
						|
        {
 | 
						|
            throw std::bad_alloc();
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Creates a buffer from existing data.
 | 
						|
     *
 | 
						|
     * @param pData  Pointer to data.
 | 
						|
     * @param size   The size of the data.
 | 
						|
     *
 | 
						|
     * @attention  @c std::bad_alloc is thrown if the allocation fails.
 | 
						|
     */
 | 
						|
    Buffer(const void* pData, size_t size)
 | 
						|
        : m_pBuffer(gwbuf_alloc_and_load(size, pData))
 | 
						|
    {
 | 
						|
        if (!m_pBuffer)
 | 
						|
        {
 | 
						|
            throw std::bad_alloc();
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Creates a buffer from a std::vector.
 | 
						|
     *
 | 
						|
     * @param data  The data to be copied.
 | 
						|
     *
 | 
						|
     * @attention  @c std::bad_alloc is thrown if the allocation fails.
 | 
						|
     */
 | 
						|
    Buffer(const std::vector<uint8_t>& data)
 | 
						|
        : m_pBuffer(gwbuf_alloc(data.size()))
 | 
						|
    {
 | 
						|
        if (m_pBuffer)
 | 
						|
        {
 | 
						|
            std::copy(data.begin(), data.end(), GWBUF_DATA(m_pBuffer));
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            throw std::bad_alloc();
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Destructor
 | 
						|
     */
 | 
						|
    ~Buffer()
 | 
						|
    {
 | 
						|
        reset();
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Assignment operator
 | 
						|
     *
 | 
						|
     * @param rhs  The @c Buffer to be assigned to this.
 | 
						|
     *
 | 
						|
     * @return this
 | 
						|
     *
 | 
						|
     * @attention  The @c Buffer provided as argument will be copied, which
 | 
						|
     *             may cause @c std::bad_alloc to be thrown.
 | 
						|
     *
 | 
						|
     * @attention  Does not invalidates iterators, but after the call, the iterators
 | 
						|
     *             will refer to the data of the other @c Buffer.
 | 
						|
     *
 | 
						|
     * @see Buffer::copy_from
 | 
						|
     */
 | 
						|
    Buffer& operator=(const Buffer& rhs)
 | 
						|
    {
 | 
						|
        Buffer temp(rhs);
 | 
						|
        swap(temp);
 | 
						|
        return *this;
 | 
						|
    }
 | 
						|
 | 
						|
#if __cplusplus >= 201103
 | 
						|
    /**
 | 
						|
     * Move assignment operator
 | 
						|
     *
 | 
						|
     * @param rhs  The @c Buffer to be moves.
 | 
						|
     */
 | 
						|
    Buffer& operator=(Buffer&& rhs)
 | 
						|
    {
 | 
						|
        reset();
 | 
						|
        swap(rhs);
 | 
						|
        return *this;
 | 
						|
    }
 | 
						|
#endif
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns a forward iterator to the beginning of the Buffer.
 | 
						|
     *
 | 
						|
     * @return  A forward iterator.
 | 
						|
     */
 | 
						|
    iterator begin()
 | 
						|
    {
 | 
						|
        return iterator(m_pBuffer);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns a forward iterator to the end of the Buffer.
 | 
						|
     *
 | 
						|
     * @return  A forward iterator.
 | 
						|
     */
 | 
						|
    iterator end()
 | 
						|
    {
 | 
						|
        return iterator();
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns a const forward iterator to the beginning of the Buffer.
 | 
						|
     *
 | 
						|
     * @return  A const forward iterator.
 | 
						|
     */
 | 
						|
    const_iterator begin() const
 | 
						|
    {
 | 
						|
        return const_iterator(m_pBuffer);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns a const forward iterator to the end of the Buffer.
 | 
						|
     *
 | 
						|
     * @return  A const forward iterator.
 | 
						|
     */
 | 
						|
    const_iterator end() const
 | 
						|
    {
 | 
						|
        return const_iterator();
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Swap the contents with another @c Buffer
 | 
						|
     *
 | 
						|
     * @param buffer  The @c Buffer to swap contents with.
 | 
						|
     */
 | 
						|
    void swap(Buffer& buffer)
 | 
						|
    {
 | 
						|
        GWBUF* pBuffer = buffer.m_pBuffer;
 | 
						|
        buffer.m_pBuffer = m_pBuffer;
 | 
						|
        m_pBuffer = pBuffer;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Clones the underlying @c GWBUF of the provided @c Buffer, and frees
 | 
						|
     * the current buffer. Effectively an assignment operator that does
 | 
						|
     * not throw.
 | 
						|
     *
 | 
						|
     * @param rhs  The @c Buffer to be copied.
 | 
						|
     *
 | 
						|
     * @return  True, if the buffer could be copied.
 | 
						|
     *
 | 
						|
     * @attention  Invalidates all iterators.
 | 
						|
     *
 | 
						|
     * @see Buffer::operator =
 | 
						|
     */
 | 
						|
    bool copy_from(const Buffer& rhs)
 | 
						|
    {
 | 
						|
        return copy_from(rhs.m_pBuffer);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Clone a GWBUF and free the current buffer
 | 
						|
     *
 | 
						|
     * @param buf Buffer to clone
 | 
						|
     *
 | 
						|
     * @return True if buffer was copied
 | 
						|
     *
 | 
						|
     * @attention  Invalidates all iterators.
 | 
						|
     */
 | 
						|
    bool copy_from(GWBUF* pBuffer)
 | 
						|
    {
 | 
						|
        bool copied = true;
 | 
						|
 | 
						|
        if (pBuffer)
 | 
						|
        {
 | 
						|
            pBuffer = gwbuf_clone(pBuffer);
 | 
						|
 | 
						|
            if (!pBuffer)
 | 
						|
            {
 | 
						|
                copied = false;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if (copied)
 | 
						|
        {
 | 
						|
            reset(pBuffer);
 | 
						|
        }
 | 
						|
 | 
						|
        return copied;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Compare content with another @ Buffer
 | 
						|
     *
 | 
						|
     * @param buffer  The buffer to compare with.
 | 
						|
     *
 | 
						|
     * @return  0 if identical,
 | 
						|
     *         -1 if this less that @c buffer, and
 | 
						|
     *         +1 if @c buffer less than this.
 | 
						|
     */
 | 
						|
    int compare(const Buffer& buffer) const
 | 
						|
    {
 | 
						|
        return gwbuf_compare(m_pBuffer, buffer.m_pBuffer);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Compare content with a @c GWBUF
 | 
						|
     *
 | 
						|
     * @param buffer  The buffer to compare with.
 | 
						|
     *
 | 
						|
     * @return  0 if identical,
 | 
						|
     *         -1 if this less that @c buffer, and
 | 
						|
     *         +1 if @c buffer less than this.
 | 
						|
     */
 | 
						|
    int compare(const GWBUF& buffer) const
 | 
						|
    {
 | 
						|
        return gwbuf_compare(m_pBuffer, &buffer);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Is content identical
 | 
						|
     *
 | 
						|
     * @param buffer  The buffer to compare with.
 | 
						|
     *
 | 
						|
     * @return True, if identical, otherwise false.
 | 
						|
     */
 | 
						|
    bool eq(const Buffer& buffer) const
 | 
						|
    {
 | 
						|
        return compare(buffer) == 0;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Is content identical.
 | 
						|
     *
 | 
						|
     * @param pBuffer  The buffer to compare with.
 | 
						|
     *
 | 
						|
     * @return True, if identical, otherwise false.
 | 
						|
     */
 | 
						|
    bool eq(const GWBUF& buffer) const
 | 
						|
    {
 | 
						|
        return compare(buffer) == 0;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Appends a @GWBUF to this.
 | 
						|
     *
 | 
						|
     * @param pBuffer  The buffer to be appended to this @c Buffer. Becomes
 | 
						|
     *                 the property of the buffer.
 | 
						|
     *
 | 
						|
     * @return this
 | 
						|
     *
 | 
						|
     * @attention  Does not invalidate any iterators, but an iterator
 | 
						|
     *             that has reached the end will remain there.
 | 
						|
     */
 | 
						|
    Buffer& append(GWBUF* pBuffer)
 | 
						|
    {
 | 
						|
        m_pBuffer = gwbuf_append(m_pBuffer, pBuffer);
 | 
						|
        return *this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Appends a @Buffer to this.
 | 
						|
     *
 | 
						|
     * @param buffer  The buffer to be appended to this Buffer.
 | 
						|
     *
 | 
						|
     * @return this
 | 
						|
     *
 | 
						|
     * @attention After the call, the @c Buffer provided as argument
 | 
						|
     *            will be empty.
 | 
						|
     *
 | 
						|
     * @attention  Does not invalidate any iterators, but an iterator
 | 
						|
     *             that has reached the end will remain there.
 | 
						|
     */
 | 
						|
    Buffer& append(Buffer& buffer)
 | 
						|
    {
 | 
						|
        m_pBuffer = gwbuf_append(m_pBuffer, buffer.release());
 | 
						|
        return *this;
 | 
						|
    }
 | 
						|
 | 
						|
    iterator erase(const_iterator first, const_iterator last)
 | 
						|
    {
 | 
						|
        if (first == end())
 | 
						|
        {
 | 
						|
            // Nothing to do
 | 
						|
            return end();
 | 
						|
        }
 | 
						|
        else if (first == last)
 | 
						|
        {
 | 
						|
            // Empty range deletion is a no-op that must return a non-const version of the given iterators
 | 
						|
            iterator it = begin();
 | 
						|
            it.advance(std::distance(const_iterator(it), first));
 | 
						|
            mxb_assert(const_iterator(it) == first);
 | 
						|
            return it;
 | 
						|
        }
 | 
						|
        else if (first == begin() && last == end())
 | 
						|
        {
 | 
						|
            // Clear out the whole buffer
 | 
						|
            reset();
 | 
						|
            return end();
 | 
						|
        }
 | 
						|
 | 
						|
        iterator rval;
 | 
						|
        const_iterator b = begin();
 | 
						|
        auto offset = std::distance(b, first);
 | 
						|
        auto num_bytes = std::distance(first, last);
 | 
						|
        mxb_assert(num_bytes > 0);
 | 
						|
 | 
						|
        auto head = gwbuf_split(&m_pBuffer, offset);
 | 
						|
 | 
						|
        if (m_pBuffer && (m_pBuffer = gwbuf_consume(m_pBuffer, num_bytes)))
 | 
						|
        {
 | 
						|
            if (head)
 | 
						|
            {
 | 
						|
                m_pBuffer = gwbuf_append(head, m_pBuffer);
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                mxb_assert(offset == 0);
 | 
						|
            }
 | 
						|
 | 
						|
            rval = begin();
 | 
						|
            rval.advance(offset + 1);
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            m_pBuffer = head;
 | 
						|
            rval = end();
 | 
						|
        }
 | 
						|
 | 
						|
        return rval;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the underlying GWBUF.
 | 
						|
     *
 | 
						|
     * @return  The underlying @c GWBUF.
 | 
						|
     *
 | 
						|
     * @attention This does not release ownership of the buffer. The returned pointer must never be
 | 
						|
     *            freed by the caller.
 | 
						|
     */
 | 
						|
    GWBUF* get()
 | 
						|
    {
 | 
						|
        return m_pBuffer;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Resets the underlying GWBUF.
 | 
						|
     *
 | 
						|
     * @param pBuffer  The @c GWBUF the @c Buffer should be reset with.
 | 
						|
     *
 | 
						|
     * @attention  The ownership of @c pBuffer is moved to the @c Buffer.
 | 
						|
     *
 | 
						|
     * @attention  Invalidates all iterators.
 | 
						|
     */
 | 
						|
    void reset(GWBUF* pBuffer = NULL)
 | 
						|
    {
 | 
						|
        gwbuf_free(m_pBuffer);
 | 
						|
        m_pBuffer = pBuffer;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Releases the underlying GWBUF.
 | 
						|
     *
 | 
						|
     * @return  The underlying @c GWBUF.
 | 
						|
     *
 | 
						|
     * @attention  The ownership of the buffer is transferred to the caller.
 | 
						|
     *
 | 
						|
     * @attention  Does not invalidate existing iterators, but any manipulation
 | 
						|
     *             of the returned @c GWBUF may invalidate them.
 | 
						|
     */
 | 
						|
    GWBUF* release()
 | 
						|
    {
 | 
						|
        GWBUF* pBuffer = m_pBuffer;
 | 
						|
        m_pBuffer = NULL;
 | 
						|
        return pBuffer;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the address of the underlying @ GWBUF. This is intended to only
 | 
						|
     * be used in a context where a function returns a @c GWBUF as an out argument.
 | 
						|
     * For instance:
 | 
						|
     *
 | 
						|
     *    void get_gwbuf(GWBUF** ppBuffer);
 | 
						|
     *    ...
 | 
						|
     *    Buffer buffer;
 | 
						|
     *
 | 
						|
     *    get_gwbuf(&buffer);
 | 
						|
     *
 | 
						|
     * @return  The address of the internal @c GWBUF pointer.
 | 
						|
     *
 | 
						|
     * @attention If the @c Buffer already refers to a @c GWBUF, that underlying
 | 
						|
     *            buffer will first be freed.
 | 
						|
     *
 | 
						|
     * @attention Invalidates all iterators.
 | 
						|
     */
 | 
						|
    GWBUF** operator&()
 | 
						|
    {
 | 
						|
        reset();
 | 
						|
        return &m_pBuffer;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * The total length of the buffer.
 | 
						|
     *
 | 
						|
     * @return The total length of the buffer.
 | 
						|
     */
 | 
						|
    size_t length() const
 | 
						|
    {
 | 
						|
        return m_pBuffer ? gwbuf_length(m_pBuffer) : 0;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Whether the buffer is empty.
 | 
						|
     *
 | 
						|
     * @return True if the buffer is empty
 | 
						|
     */
 | 
						|
    bool empty() const
 | 
						|
    {
 | 
						|
        return m_pBuffer == nullptr;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Whether the buffer is contiguous.
 | 
						|
     *
 | 
						|
     * @return  True, if the buffer is contiguous.
 | 
						|
     */
 | 
						|
    bool is_contiguous() const
 | 
						|
    {
 | 
						|
        return GWBUF_IS_CONTIGUOUS(m_pBuffer);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Make the buffer contiguous.
 | 
						|
     *
 | 
						|
     * @return  True, if the buffer could be made contiguous.
 | 
						|
     *
 | 
						|
     * @attention  Invalidates all iterators.
 | 
						|
     */
 | 
						|
    bool make_contiguous(std::nothrow_t)
 | 
						|
    {
 | 
						|
        GWBUF* pBuffer = gwbuf_make_contiguous(m_pBuffer);
 | 
						|
 | 
						|
        if (pBuffer)
 | 
						|
        {
 | 
						|
            m_pBuffer = pBuffer;
 | 
						|
        }
 | 
						|
 | 
						|
        return pBuffer != NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Make the buffer contiguous.
 | 
						|
     *
 | 
						|
     * @throws  @c std::bad_alloc if an allocation failed.
 | 
						|
     *
 | 
						|
     * @attention  Invalidates all iterators.
 | 
						|
     */
 | 
						|
    void make_contiguous()
 | 
						|
    {
 | 
						|
        if (!make_contiguous(std::nothrow))
 | 
						|
        {
 | 
						|
            mxb_assert(!true);
 | 
						|
            throw std::bad_alloc();
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Debug function for dumping buffer contents to log
 | 
						|
     *
 | 
						|
     * Prints contents as hexadecimal. Only the first 1024 bytes are dumped to avoid filling up the log.
 | 
						|
     *
 | 
						|
     * @param log_level Log priority where the message is written
 | 
						|
     */
 | 
						|
    void hexdump(int log_level = LOG_INFO) const;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Debug function for pretty-printing buffer contents to log
 | 
						|
     *
 | 
						|
     * The output format is similar to `hexdump -C` and provides both hex and human-readable values.
 | 
						|
     *
 | 
						|
     * @param log_level Log priority where the message is written
 | 
						|
     */
 | 
						|
    void hexdump_pretty(int log_level = LOG_INFO) const;
 | 
						|
 | 
						|
private:
 | 
						|
    // To prevent @c Buffer from being created on the heap.
 | 
						|
    void* operator new(size_t);         // standard new
 | 
						|
    void* operator new(size_t, void*);  // placement new
 | 
						|
    void* operator new[](size_t);       // array new
 | 
						|
    void* operator new[](size_t, void*);// placement array new
 | 
						|
 | 
						|
private:
 | 
						|
    GWBUF* m_pBuffer;
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Checks two @c Buffers for equality.
 | 
						|
 *
 | 
						|
 * @return True if equal, false otherwise.
 | 
						|
 */
 | 
						|
inline bool operator==(const Buffer& lhs, const Buffer& rhs)
 | 
						|
{
 | 
						|
    return lhs.eq(rhs);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Checks a @c Buffer and a @c GWBUF for equality.
 | 
						|
 *
 | 
						|
 * @return True if equal, false otherwise.
 | 
						|
 */
 | 
						|
inline bool operator==(const Buffer& lhs, const GWBUF& rhs)
 | 
						|
{
 | 
						|
    return lhs.eq(rhs);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Checks two @c Buffers for un-equality.
 | 
						|
 *
 | 
						|
 * @return True if un-equal, false otherwise.
 | 
						|
 */
 | 
						|
inline bool operator!=(const Buffer& lhs, const Buffer& rhs)
 | 
						|
{
 | 
						|
    return !lhs.eq(rhs);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Checks a @c Buffer and a @c GWBUF for un-equality.
 | 
						|
 *
 | 
						|
 * @return True if un-equal, false otherwise.
 | 
						|
 */
 | 
						|
inline bool operator!=(const Buffer& lhs, const GWBUF& rhs)
 | 
						|
{
 | 
						|
    return !lhs.eq(rhs);
 | 
						|
}
 | 
						|
}
 |