311 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			311 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights
 | 
						|
reserved.
 | 
						|
 | 
						|
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; version 2 of
 | 
						|
the License.
 | 
						|
 | 
						|
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 St, Fifth Floor, Boston, MA
 | 
						|
02110-1301  USA
 | 
						|
*/
 | 
						|
#ifndef _PROTOCOL_H
 | 
						|
#define	_PROTOCOL_H
 | 
						|
 | 
						|
#include <boost/asio.hpp>
 | 
						|
#include <list>
 | 
						|
#include "binlog_event.h"
 | 
						|
 | 
						|
using boost::asio::ip::tcp;
 | 
						|
namespace mysql {
 | 
						|
namespace system {
 | 
						|
 | 
						|
/**
 | 
						|
  Storage structure for the handshake package sent from the server to
 | 
						|
  the client.
 | 
						|
*/
 | 
						|
struct st_handshake_package
 | 
						|
{
 | 
						|
  boost::uint8_t     protocol_version;
 | 
						|
  std::string server_version_str;
 | 
						|
  boost::uint32_t    thread_id;
 | 
						|
  boost::uint8_t     scramble_buff[8];
 | 
						|
  boost::uint16_t    server_capabilities;
 | 
						|
  boost::uint8_t     server_language;
 | 
						|
  boost::uint16_t    server_status;
 | 
						|
  boost::uint8_t     scramble_buff2[13];
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
  Storage structure for the OK package sent from the server to
 | 
						|
  the client.
 | 
						|
*/
 | 
						|
struct st_ok_package
 | 
						|
{
 | 
						|
  boost::uint8_t  result_type;
 | 
						|
  boost::uint64_t affected_rows;
 | 
						|
  boost::uint64_t insert_id;
 | 
						|
  boost::uint16_t server_status;
 | 
						|
  boost::uint16_t warning_count;
 | 
						|
  std::string  message;
 | 
						|
};
 | 
						|
 | 
						|
struct st_eof_package
 | 
						|
{
 | 
						|
  boost::uint16_t warning_count;
 | 
						|
  boost::uint16_t status_flags;
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
  Storage structure for the Error package sent from the server to
 | 
						|
  the client.
 | 
						|
*/
 | 
						|
struct st_error_package
 | 
						|
{
 | 
						|
  boost::uint16_t error_code;
 | 
						|
  boost::uint8_t  sql_state[5];
 | 
						|
  std::string  message;
 | 
						|
};
 | 
						|
 | 
						|
void write_packet_header(char *buff, boost::uint16_t size, boost::uint8_t packet_no);
 | 
						|
 | 
						|
class Protocol_validator;
 | 
						|
class buffer_source;
 | 
						|
 | 
						|
/**
 | 
						|
 * The Protocol interface is used to describe a grammar consisting of
 | 
						|
 * chunks of bytes that are read or written in consequtive order.
 | 
						|
 * Example:
 | 
						|
 * class Protocol_impl : public Protocol;
 | 
						|
 * Protocol_impl chunk1(chunk_datastore1);
 | 
						|
 * Protocol_impl chunk2(chunk_datastore2);
 | 
						|
 * input_stream >> chunk1
 | 
						|
 *              >> chunk2;
 | 
						|
 */
 | 
						|
class Protocol
 | 
						|
{
 | 
						|
public:
 | 
						|
  Protocol() { m_length_encoded_binary= false; }
 | 
						|
  /**
 | 
						|
    Return the number of bytes which is read or written by this protocol chunk.
 | 
						|
    The default size is equal to the underlying storage data type.
 | 
						|
  */
 | 
						|
  virtual unsigned int size()=0;
 | 
						|
 | 
						|
  /** Return a pointer to the first byte in a linear storage buffer */
 | 
						|
  virtual const char *data()=0;
 | 
						|
 | 
						|
  /**
 | 
						|
    Change the number of bytes which will be read or written to the storage.
 | 
						|
    The default size is euqal to the storage type size. This can change if the
 | 
						|
    protocol is reading a length encoded binary.
 | 
						|
    The new size must always be less than the size of the underlying storage
 | 
						|
    type.
 | 
						|
  */
 | 
						|
  virtual void collapse_size(unsigned int new_size)=0;
 | 
						|
 | 
						|
  /**
 | 
						|
    The first byte will have a special interpretation which will indicate
 | 
						|
    how many bytes should be read next.
 | 
						|
  */
 | 
						|
  void set_length_encoded_binary(bool bswitch) { m_length_encoded_binary= bswitch; }
 | 
						|
  bool is_length_encoded_binary(void) { return m_length_encoded_binary; }
 | 
						|
 | 
						|
private:
 | 
						|
    bool m_length_encoded_binary;
 | 
						|
 | 
						|
    friend std::istream &operator<<(std::istream &is, Protocol &chunk);
 | 
						|
    friend std::istream &operator>>(std::istream &is, Protocol &chunk);
 | 
						|
    friend buffer_source &operator>>(buffer_source &src, Protocol &chunk);
 | 
						|
    friend std::istream &operator>>(std::istream &is, std::string &str);
 | 
						|
};
 | 
						|
 | 
						|
template<typename T>
 | 
						|
class Protocol_chunk : public Protocol
 | 
						|
{
 | 
						|
public:
 | 
						|
 | 
						|
  Protocol_chunk() : Protocol()
 | 
						|
  {
 | 
						|
    m_size= 0;
 | 
						|
    m_data= 0;
 | 
						|
  }
 | 
						|
 | 
						|
  Protocol_chunk(T &chunk) : Protocol()
 | 
						|
  {
 | 
						|
    m_data= (const char *)&chunk;
 | 
						|
    m_size= sizeof(T);
 | 
						|
  }
 | 
						|
 | 
						|
  Protocol_chunk(const T &chunk) : Protocol ()
 | 
						|
  {
 | 
						|
     m_data= (const char *) &chunk;
 | 
						|
     m_size= sizeof(T);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * @param buffer A pointer to the storage
 | 
						|
   * @param size The size of the storage
 | 
						|
   *
 | 
						|
   * @note If size == 0 then the chunk is a
 | 
						|
   * length coded binary.
 | 
						|
   */
 | 
						|
  Protocol_chunk(T *buffer, unsigned long size) : Protocol ()
 | 
						|
  {
 | 
						|
      m_data= (const char *)buffer;
 | 
						|
      m_size= size;
 | 
						|
  }
 | 
						|
 | 
						|
  virtual unsigned int size() { return m_size; }
 | 
						|
  virtual const char *data() { return m_data; }
 | 
						|
  virtual void collapse_size(unsigned int new_size)
 | 
						|
  {
 | 
						|
    //assert(new_size <= m_size);
 | 
						|
    memset((char *)m_data+new_size,'\0', m_size-new_size);
 | 
						|
    m_size= new_size;
 | 
						|
  }
 | 
						|
private:
 | 
						|
  const char *m_data;
 | 
						|
  unsigned long m_size;
 | 
						|
};
 | 
						|
 | 
						|
std::ostream &operator<<(std::ostream &os, Protocol &chunk);
 | 
						|
 | 
						|
typedef Protocol_chunk<boost::uint8_t> Protocol_chunk_uint8;
 | 
						|
 | 
						|
class Protocol_chunk_string //: public Protocol_chunk_uint8
 | 
						|
{
 | 
						|
public:
 | 
						|
    Protocol_chunk_string(std::string &chunk, unsigned long size) //: Protocol_chunk_uint8()
 | 
						|
    {
 | 
						|
        m_str= &chunk;
 | 
						|
        m_str->assign(size,'*');
 | 
						|
    }
 | 
						|
 | 
						|
    virtual unsigned int size() const { return m_str->size(); }
 | 
						|
    virtual const char *data() const { return m_str->data(); }
 | 
						|
    virtual void collapse_size(unsigned int new_size)
 | 
						|
    {
 | 
						|
        m_str->resize(new_size);
 | 
						|
    }
 | 
						|
private:
 | 
						|
    friend std::istream &operator>>(std::istream &is, Protocol_chunk_string &str);
 | 
						|
    std::string *m_str;
 | 
						|
};
 | 
						|
 | 
						|
class Protocol_chunk_vector : public Protocol_chunk_uint8
 | 
						|
{
 | 
						|
public:
 | 
						|
    Protocol_chunk_vector(std::vector<boost::uint8_t> &chunk, unsigned long size)
 | 
						|
      : Protocol_chunk_uint8()
 | 
						|
    {
 | 
						|
        m_vec= &chunk;
 | 
						|
        m_vec->reserve(size);
 | 
						|
        m_size= size;
 | 
						|
    }
 | 
						|
 | 
						|
    virtual unsigned int size() { return m_vec->size(); }
 | 
						|
    virtual const char *data() { return reinterpret_cast<const char *>(&*m_vec->begin()); }
 | 
						|
    virtual void collapse_size(unsigned int new_size)
 | 
						|
    {
 | 
						|
        m_vec->resize(new_size);
 | 
						|
    }
 | 
						|
private:
 | 
						|
    friend std::istream &operator>>(std::istream &is, Protocol_chunk_vector &chunk);
 | 
						|
    std::vector<boost::uint8_t> *m_vec;
 | 
						|
    unsigned long m_size;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
std::istream &operator>>(std::istream &is, Protocol_chunk_vector &chunk);
 | 
						|
 | 
						|
class buffer_source
 | 
						|
{
 | 
						|
public:
 | 
						|
 | 
						|
    buffer_source(const char *src, int sz)
 | 
						|
    {
 | 
						|
        m_src= src;
 | 
						|
        m_size= sz;
 | 
						|
        m_ptr= 0;
 | 
						|
    }
 | 
						|
 | 
						|
    friend buffer_source &operator>>(buffer_source &src, Protocol &chunk);
 | 
						|
private:
 | 
						|
    const char *m_src;
 | 
						|
    int m_size;
 | 
						|
    int m_ptr;
 | 
						|
 | 
						|
};
 | 
						|
 | 
						|
class Protocol_chunk_string_len
 | 
						|
{
 | 
						|
public:
 | 
						|
    Protocol_chunk_string_len(std::string &str)
 | 
						|
    {
 | 
						|
        m_storage= &str;
 | 
						|
    }
 | 
						|
 | 
						|
private:
 | 
						|
    friend std::istream &operator>>(std::istream &is, Protocol_chunk_string_len &lenstr);
 | 
						|
    std::string *m_storage;
 | 
						|
};
 | 
						|
 | 
						|
buffer_source &operator>>(buffer_source &src, Protocol &chunk);
 | 
						|
/** TODO assert that the correct endianess is used */
 | 
						|
std::istream &operator>>(std::istream &is, Protocol &chunk);
 | 
						|
std::istream &operator>>(std::istream &is, std::string &str);
 | 
						|
std::istream &operator>>(std::istream &is, Protocol_chunk_string_len &lenstr);
 | 
						|
std::istream &operator>>(std::istream &is, Protocol_chunk_string &str);
 | 
						|
 | 
						|
int proto_read_package_header(tcp::socket *socket, unsigned long *packet_length, unsigned char *packet_no);
 | 
						|
 | 
						|
/**
 | 
						|
 * Read a server package header from a stream buffer
 | 
						|
 *
 | 
						|
 * @retval 0 Success
 | 
						|
 * @retval >0 An error occurred
 | 
						|
 */
 | 
						|
int proto_read_package_header(tcp::socket *socket, boost::asio::streambuf &buff, unsigned long *packet_length, unsigned char *packet_no);
 | 
						|
 | 
						|
/**
 | 
						|
 * Get one complete packet from the server
 | 
						|
 *
 | 
						|
 * @param socket Pointer to the active tcp-socket
 | 
						|
 * @param buff A reference to a stream buffer
 | 
						|
 * @param packet_no [out] The number of the packet as given by the server
 | 
						|
 *
 | 
						|
 * @return the size of the packet or 0 to indicate an error
 | 
						|
 */
 | 
						|
int proto_get_one_package(tcp::socket *socket, boost::asio::streambuf &buff, boost::uint8_t *packet_no);
 | 
						|
void prot_parse_error_message(std::istream &is, struct st_error_package &err, int packet_length);
 | 
						|
void prot_parse_ok_message(std::istream &is, struct st_ok_package &ok, int packet_length);
 | 
						|
void prot_parse_eof_message(std::istream &is, struct st_eof_package &eof);
 | 
						|
void proto_get_handshake_package(std::istream &is, struct st_handshake_package &p, int packet_length);
 | 
						|
 | 
						|
/**
 | 
						|
  Allocates a new event and copy the header. The caller must be responsible for
 | 
						|
  releasing the allocated memory.
 | 
						|
*/
 | 
						|
Query_event *proto_query_event(std::istream &is, Log_event_header *header);
 | 
						|
Rotate_event *proto_rotate_event(std::istream &is, Log_event_header *header);
 | 
						|
Incident_event *proto_incident_event(std::istream &is, Log_event_header *header);
 | 
						|
Row_event *proto_rows_event(std::istream &is, Log_event_header *header);
 | 
						|
Table_map_event *proto_table_map_event(std::istream &is, Log_event_header *header);
 | 
						|
Int_var_event *proto_intvar_event(std::istream &is, Log_event_header *header);
 | 
						|
User_var_event *proto_uservar_event(std::istream &is, Log_event_header *header);
 | 
						|
Gtid_event *proto_gtid_event(std::istream &is, Log_event_header *header);
 | 
						|
 | 
						|
} // end namespace system
 | 
						|
} // end namespace mysql
 | 
						|
 | 
						|
#endif	/* _PROTOCOL_H */
 |