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 */
|