2019-03-16 02:08:21 +00:00
|
|
|
#pragma once
|
|
|
|
|
2019-07-01 05:58:31 +00:00
|
|
|
#include <Common/MemoryTracker.h>
|
|
|
|
#include <Common/PODArray.h>
|
2019-05-26 06:52:29 +00:00
|
|
|
#include <Core/Types.h>
|
2019-03-26 18:30:41 +00:00
|
|
|
#include <IO/copyData.h>
|
2019-05-26 06:52:29 +00:00
|
|
|
#include <IO/ReadBuffer.h>
|
2019-07-01 05:58:31 +00:00
|
|
|
#include <IO/ReadBufferFromMemory.h>
|
2019-04-29 06:05:30 +00:00
|
|
|
#include <IO/ReadBufferFromPocoSocket.h>
|
2019-07-01 05:58:31 +00:00
|
|
|
#include <IO/ReadHelpers.h>
|
2019-05-26 06:52:29 +00:00
|
|
|
#include <IO/WriteBuffer.h>
|
2019-04-29 06:05:30 +00:00
|
|
|
#include <IO/WriteBufferFromPocoSocket.h>
|
2019-05-16 03:34:04 +00:00
|
|
|
#include <IO/WriteBufferFromString.h>
|
2019-07-01 05:58:31 +00:00
|
|
|
#include <IO/WriteHelpers.h>
|
2019-04-29 06:05:30 +00:00
|
|
|
#include <Poco/Net/StreamSocket.h>
|
2019-05-26 06:52:29 +00:00
|
|
|
#include <Poco/RandomStream.h>
|
2019-03-16 02:08:21 +00:00
|
|
|
#include <random>
|
|
|
|
#include <sstream>
|
|
|
|
|
|
|
|
/// Implementation of MySQL wire protocol
|
|
|
|
|
2019-03-26 18:30:41 +00:00
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
|
|
|
extern const int UNKNOWN_PACKET_FROM_CLIENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace MySQLProtocol
|
|
|
|
{
|
2019-03-16 02:08:21 +00:00
|
|
|
|
|
|
|
const size_t MAX_PACKET_LENGTH = (1 << 24) - 1; // 16 mb
|
|
|
|
const size_t SCRAMBLE_LENGTH = 20;
|
|
|
|
const size_t AUTH_PLUGIN_DATA_PART_1_LENGTH = 8;
|
|
|
|
const size_t MYSQL_ERRMSG_SIZE = 512;
|
2019-05-16 17:15:43 +00:00
|
|
|
const size_t PACKET_HEADER_SIZE = 4;
|
|
|
|
const size_t SSL_REQUEST_PAYLOAD_SIZE = 32;
|
2019-03-16 02:08:21 +00:00
|
|
|
|
2019-03-26 18:30:41 +00:00
|
|
|
namespace Authentication
|
|
|
|
{
|
2019-05-16 17:15:43 +00:00
|
|
|
const String SHA256 = "sha256_password"; /// Caching SHA2 plugin is not used because it would be possible to authenticate knowing hash from users.xml.
|
2019-03-16 02:08:21 +00:00
|
|
|
}
|
|
|
|
|
2019-03-26 18:30:41 +00:00
|
|
|
enum CharacterSet
|
|
|
|
{
|
|
|
|
utf8_general_ci = 33,
|
|
|
|
binary = 63
|
2019-03-16 02:08:21 +00:00
|
|
|
};
|
|
|
|
|
2019-03-26 18:30:41 +00:00
|
|
|
enum StatusFlags
|
|
|
|
{
|
2019-03-16 02:08:21 +00:00
|
|
|
SERVER_SESSION_STATE_CHANGED = 0x4000
|
|
|
|
};
|
|
|
|
|
2019-03-26 18:30:41 +00:00
|
|
|
enum Capability
|
|
|
|
{
|
2019-03-16 02:08:21 +00:00
|
|
|
CLIENT_CONNECT_WITH_DB = 0x00000008,
|
|
|
|
CLIENT_PROTOCOL_41 = 0x00000200,
|
2019-04-29 06:05:30 +00:00
|
|
|
CLIENT_SSL = 0x00000800,
|
2019-03-16 02:08:21 +00:00
|
|
|
CLIENT_TRANSACTIONS = 0x00002000, // TODO
|
|
|
|
CLIENT_SESSION_TRACK = 0x00800000, // TODO
|
|
|
|
CLIENT_SECURE_CONNECTION = 0x00008000,
|
|
|
|
CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA = 0x00200000,
|
|
|
|
CLIENT_PLUGIN_AUTH = 0x00080000,
|
|
|
|
CLIENT_DEPRECATE_EOF = 0x01000000,
|
|
|
|
};
|
|
|
|
|
2019-03-26 18:30:41 +00:00
|
|
|
enum Command
|
|
|
|
{
|
2019-03-16 02:08:21 +00:00
|
|
|
COM_SLEEP = 0x0,
|
|
|
|
COM_QUIT = 0x1,
|
|
|
|
COM_INIT_DB = 0x2,
|
|
|
|
COM_QUERY = 0x3,
|
|
|
|
COM_FIELD_LIST = 0x4,
|
|
|
|
COM_CREATE_DB = 0x5,
|
|
|
|
COM_DROP_DB = 0x6,
|
|
|
|
COM_REFRESH = 0x7,
|
|
|
|
COM_SHUTDOWN = 0x8,
|
|
|
|
COM_STATISTICS = 0x9,
|
|
|
|
COM_PROCESS_INFO = 0xa,
|
|
|
|
COM_CONNECT = 0xb,
|
|
|
|
COM_PROCESS_KILL = 0xc,
|
|
|
|
COM_DEBUG = 0xd,
|
|
|
|
COM_PING = 0xe,
|
|
|
|
COM_TIME = 0xf,
|
|
|
|
COM_DELAYED_INSERT = 0x10,
|
|
|
|
COM_CHANGE_USER = 0x11,
|
|
|
|
COM_RESET_CONNECTION = 0x1f,
|
|
|
|
COM_DAEMON = 0x1d
|
|
|
|
};
|
|
|
|
|
2019-03-26 18:30:41 +00:00
|
|
|
enum ColumnType
|
|
|
|
{
|
2019-03-16 02:08:21 +00:00
|
|
|
MYSQL_TYPE_DECIMAL = 0x00,
|
|
|
|
MYSQL_TYPE_TINY = 0x01,
|
|
|
|
MYSQL_TYPE_SHORT = 0x02,
|
|
|
|
MYSQL_TYPE_LONG = 0x03,
|
|
|
|
MYSQL_TYPE_FLOAT = 0x04,
|
|
|
|
MYSQL_TYPE_DOUBLE = 0x05,
|
|
|
|
MYSQL_TYPE_NULL = 0x06,
|
|
|
|
MYSQL_TYPE_TIMESTAMP = 0x07,
|
|
|
|
MYSQL_TYPE_LONGLONG = 0x08,
|
|
|
|
MYSQL_TYPE_INT24 = 0x09,
|
|
|
|
MYSQL_TYPE_DATE = 0x0a,
|
|
|
|
MYSQL_TYPE_TIME = 0x0b,
|
|
|
|
MYSQL_TYPE_DATETIME = 0x0c,
|
|
|
|
MYSQL_TYPE_YEAR = 0x0d,
|
|
|
|
MYSQL_TYPE_VARCHAR = 0x0f,
|
|
|
|
MYSQL_TYPE_BIT = 0x10,
|
|
|
|
MYSQL_TYPE_NEWDECIMAL = 0xf6,
|
|
|
|
MYSQL_TYPE_ENUM = 0xf7,
|
|
|
|
MYSQL_TYPE_SET = 0xf8,
|
|
|
|
MYSQL_TYPE_TINY_BLOB = 0xf9,
|
|
|
|
MYSQL_TYPE_MEDIUM_BLOB = 0xfa,
|
|
|
|
MYSQL_TYPE_LONG_BLOB = 0xfb,
|
|
|
|
MYSQL_TYPE_BLOB = 0xfc,
|
|
|
|
MYSQL_TYPE_VAR_STRING = 0xfd,
|
|
|
|
MYSQL_TYPE_STRING = 0xfe,
|
|
|
|
MYSQL_TYPE_GEOMETRY = 0xff
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2019-07-01 05:58:31 +00:00
|
|
|
// For tracking memory of packets with String fields.
|
|
|
|
class PacketMemoryTracker
|
|
|
|
{
|
|
|
|
Int64 allocated = 0;
|
|
|
|
public:
|
|
|
|
void alloc(Int64 size)
|
|
|
|
{
|
|
|
|
CurrentMemoryTracker::alloc(allocated);
|
|
|
|
allocated = size;
|
|
|
|
}
|
|
|
|
|
|
|
|
~PacketMemoryTracker()
|
|
|
|
{
|
|
|
|
CurrentMemoryTracker::free(allocated);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
using Vector = PODArray<char>;
|
|
|
|
|
|
|
|
|
2019-03-26 18:30:41 +00:00
|
|
|
class ProtocolError : public DB::Exception
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
using Exception::Exception;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class WritePacket
|
|
|
|
{
|
|
|
|
public:
|
2019-07-01 05:58:31 +00:00
|
|
|
virtual void writePayload(WriteBuffer & buffer) const = 0;
|
2019-03-16 02:08:21 +00:00
|
|
|
|
2019-03-26 18:30:41 +00:00
|
|
|
virtual ~WritePacket() = default;
|
|
|
|
};
|
2019-03-16 02:08:21 +00:00
|
|
|
|
|
|
|
|
2019-03-26 18:30:41 +00:00
|
|
|
class ReadPacket
|
|
|
|
{
|
2019-03-16 02:08:21 +00:00
|
|
|
public:
|
2019-04-29 06:05:30 +00:00
|
|
|
ReadPacket() = default;
|
2019-07-01 05:58:31 +00:00
|
|
|
ReadPacket(ReadPacket &&) = default;
|
|
|
|
virtual void readPayload(Vector && payload) = 0;
|
2019-03-26 18:30:41 +00:00
|
|
|
|
|
|
|
virtual ~ReadPacket() = default;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/* Writes and reads packets, keeping sequence-id.
|
|
|
|
* Throws ProtocolError, if packet with incorrect sequence-id was received.
|
|
|
|
*/
|
|
|
|
class PacketSender
|
|
|
|
{
|
|
|
|
public:
|
2019-05-16 03:34:04 +00:00
|
|
|
size_t & sequence_id;
|
|
|
|
ReadBuffer * in;
|
|
|
|
WriteBuffer * out;
|
2019-05-16 17:15:43 +00:00
|
|
|
size_t max_packet_size = MAX_PACKET_LENGTH;
|
2019-03-26 18:30:41 +00:00
|
|
|
|
2019-05-16 03:34:04 +00:00
|
|
|
/// For reading and writing.
|
2019-05-30 08:25:16 +00:00
|
|
|
PacketSender(ReadBuffer & in, WriteBuffer & out, size_t & sequence_id)
|
2019-05-16 03:34:04 +00:00
|
|
|
: sequence_id(sequence_id)
|
|
|
|
, in(&in)
|
|
|
|
, out(&out)
|
|
|
|
{
|
|
|
|
}
|
2019-04-29 06:05:30 +00:00
|
|
|
|
2019-05-16 03:34:04 +00:00
|
|
|
/// For writing.
|
2019-05-30 08:25:16 +00:00
|
|
|
PacketSender(WriteBuffer & out, size_t & sequence_id)
|
2019-04-29 06:05:30 +00:00
|
|
|
: sequence_id(sequence_id)
|
2019-05-16 03:34:04 +00:00
|
|
|
, in(nullptr)
|
|
|
|
, out(&out)
|
2019-03-26 18:30:41 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-07-01 05:58:31 +00:00
|
|
|
Vector receivePacketPayload()
|
2019-03-26 18:30:41 +00:00
|
|
|
{
|
2019-07-01 05:58:31 +00:00
|
|
|
Vector result;
|
|
|
|
WriteBufferFromVector<Vector> buf(result);
|
2019-03-26 18:30:41 +00:00
|
|
|
|
|
|
|
size_t payload_length = 0;
|
|
|
|
size_t packet_sequence_id = 0;
|
|
|
|
|
|
|
|
// packets which are larger than or equal to 16MB are splitted
|
|
|
|
do
|
|
|
|
{
|
|
|
|
in->readStrict(reinterpret_cast<char *>(&payload_length), 3);
|
|
|
|
|
2019-05-16 17:15:43 +00:00
|
|
|
if (payload_length > max_packet_size)
|
2019-03-26 18:30:41 +00:00
|
|
|
{
|
|
|
|
std::ostringstream tmp;
|
2019-05-16 17:15:43 +00:00
|
|
|
tmp << "Received packet with payload larger than max_packet_size: " << payload_length;
|
2019-03-26 18:30:41 +00:00
|
|
|
throw ProtocolError(tmp.str(), ErrorCodes::UNKNOWN_PACKET_FROM_CLIENT);
|
|
|
|
}
|
|
|
|
|
|
|
|
in->readStrict(reinterpret_cast<char *>(&packet_sequence_id), 1);
|
|
|
|
|
|
|
|
if (packet_sequence_id != sequence_id)
|
|
|
|
{
|
|
|
|
std::ostringstream tmp;
|
|
|
|
tmp << "Received packet with wrong sequence-id: " << packet_sequence_id << ". Expected: " << sequence_id << '.';
|
|
|
|
throw ProtocolError(tmp.str(), ErrorCodes::UNKNOWN_PACKET_FROM_CLIENT);
|
|
|
|
}
|
|
|
|
sequence_id++;
|
|
|
|
|
|
|
|
copyData(*in, static_cast<WriteBuffer &>(buf), payload_length);
|
2019-05-16 17:15:43 +00:00
|
|
|
} while (payload_length == max_packet_size);
|
2019-03-26 18:30:41 +00:00
|
|
|
|
2019-07-01 05:58:31 +00:00
|
|
|
return result;
|
2019-03-26 18:30:41 +00:00
|
|
|
}
|
|
|
|
|
2019-04-08 07:03:04 +00:00
|
|
|
void receivePacket(ReadPacket & packet)
|
2019-03-26 18:30:41 +00:00
|
|
|
{
|
2019-07-01 05:58:31 +00:00
|
|
|
auto payload = receivePacketPayload();
|
|
|
|
packet.readPayload(std::move(payload));
|
2019-03-26 18:30:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<class T>
|
|
|
|
void sendPacket(const T & packet, bool flush = false)
|
|
|
|
{
|
|
|
|
static_assert(std::is_base_of<WritePacket, T>());
|
2019-07-01 05:58:31 +00:00
|
|
|
Vector payload;
|
|
|
|
WriteBufferFromVector buffer(payload);
|
|
|
|
packet.writePayload(buffer);
|
2019-03-26 18:30:41 +00:00
|
|
|
size_t pos = 0;
|
|
|
|
do
|
|
|
|
{
|
2019-07-01 05:58:31 +00:00
|
|
|
size_t payload_length = std::min(payload.size() - pos, max_packet_size);
|
2019-03-26 18:30:41 +00:00
|
|
|
|
|
|
|
out->write(reinterpret_cast<const char *>(&payload_length), 3);
|
|
|
|
out->write(reinterpret_cast<const char *>(&sequence_id), 1);
|
|
|
|
out->write(payload.data() + pos, payload_length);
|
|
|
|
|
|
|
|
pos += payload_length;
|
|
|
|
sequence_id++;
|
2019-07-01 05:58:31 +00:00
|
|
|
} while (pos < payload.size());
|
2019-03-26 18:30:41 +00:00
|
|
|
|
|
|
|
if (flush)
|
|
|
|
out->next();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets sequence-id to 0. Must be called before each command phase.
|
|
|
|
void resetSequenceId();
|
|
|
|
|
|
|
|
/// Converts packet to text. Is used for debug output.
|
2019-07-01 05:58:31 +00:00
|
|
|
static String packetToText(const Vector & payload);
|
2019-03-16 02:08:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2019-07-01 05:58:31 +00:00
|
|
|
uint64_t readLengthEncodedNumber(ReadBuffer & ss);
|
2019-03-16 02:08:21 +00:00
|
|
|
|
2019-07-01 05:58:31 +00:00
|
|
|
void writeLengthEncodedNumber(uint64_t x, WriteBuffer & buffer);
|
2019-03-16 02:08:21 +00:00
|
|
|
|
2019-07-01 05:58:31 +00:00
|
|
|
template <class T>
|
|
|
|
void writeLengthEncodedString(const T & s, WriteBuffer & buffer)
|
|
|
|
{
|
|
|
|
writeLengthEncodedNumber(s.size(), buffer);
|
|
|
|
buffer.write(s.data(), s.size());
|
|
|
|
}
|
2019-03-26 18:30:41 +00:00
|
|
|
|
2019-07-01 05:58:31 +00:00
|
|
|
template <class T>
|
|
|
|
void writeNulTerminatedString(const T & s, WriteBuffer & buffer)
|
|
|
|
{
|
|
|
|
buffer.write(s.data(), s.size());
|
|
|
|
buffer.write(0);
|
|
|
|
}
|
2019-03-26 18:30:41 +00:00
|
|
|
|
|
|
|
|
|
|
|
class Handshake : public WritePacket
|
|
|
|
{
|
2019-03-16 02:08:21 +00:00
|
|
|
int protocol_version = 0xa;
|
2019-03-26 18:30:41 +00:00
|
|
|
String server_version;
|
2019-03-16 02:08:21 +00:00
|
|
|
uint32_t connection_id;
|
|
|
|
uint32_t capability_flags;
|
|
|
|
uint8_t character_set;
|
|
|
|
uint32_t status_flags;
|
2019-03-26 18:30:41 +00:00
|
|
|
String auth_plugin_data;
|
2019-03-16 02:08:21 +00:00
|
|
|
public:
|
2019-05-26 06:52:29 +00:00
|
|
|
explicit Handshake(uint32_t capability_flags, uint32_t connection_id, String server_version, String auth_plugin_data)
|
2019-04-22 10:57:50 +00:00
|
|
|
: protocol_version(0xa)
|
|
|
|
, server_version(std::move(server_version))
|
|
|
|
, connection_id(connection_id)
|
2019-05-26 06:52:29 +00:00
|
|
|
, capability_flags(capability_flags)
|
2019-04-22 10:57:50 +00:00
|
|
|
, character_set(CharacterSet::utf8_general_ci)
|
|
|
|
, status_flags(0)
|
2019-07-01 05:58:31 +00:00
|
|
|
, auth_plugin_data(std::move(auth_plugin_data))
|
2019-03-26 18:30:41 +00:00
|
|
|
{
|
2019-03-16 02:08:21 +00:00
|
|
|
}
|
|
|
|
|
2019-07-01 05:58:31 +00:00
|
|
|
void writePayload(WriteBuffer & buffer) const override
|
2019-03-26 18:30:41 +00:00
|
|
|
{
|
2019-07-01 05:58:31 +00:00
|
|
|
buffer.write(static_cast<char>(protocol_version));
|
|
|
|
writeNulTerminatedString(server_version, buffer);
|
|
|
|
buffer.write(reinterpret_cast<const char *>(&connection_id), 4);
|
|
|
|
writeNulTerminatedString(auth_plugin_data.substr(0, AUTH_PLUGIN_DATA_PART_1_LENGTH), buffer);
|
|
|
|
buffer.write(reinterpret_cast<const char *>(&capability_flags), 2);
|
|
|
|
buffer.write(reinterpret_cast<const char *>(&character_set), 1);
|
|
|
|
buffer.write(reinterpret_cast<const char *>(&status_flags), 2);
|
|
|
|
buffer.write((reinterpret_cast<const char *>(&capability_flags)) + 2, 2);
|
|
|
|
buffer.write(static_cast<char>(auth_plugin_data.size()));
|
|
|
|
writeChar(0x0, 10, buffer);
|
|
|
|
writeString(auth_plugin_data.substr(AUTH_PLUGIN_DATA_PART_1_LENGTH, auth_plugin_data.size() - AUTH_PLUGIN_DATA_PART_1_LENGTH), buffer);
|
|
|
|
writeString(Authentication::SHA256, buffer);
|
|
|
|
writeChar(0x0, 1, buffer);
|
2019-03-16 02:08:21 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-04-29 06:05:30 +00:00
|
|
|
class SSLRequest : public ReadPacket
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
uint32_t capability_flags;
|
|
|
|
uint32_t max_packet_size;
|
|
|
|
uint8_t character_set;
|
|
|
|
|
2019-07-01 05:58:31 +00:00
|
|
|
void readPayload(Vector && s) override
|
2019-04-29 06:05:30 +00:00
|
|
|
{
|
2019-07-01 05:58:31 +00:00
|
|
|
ReadBufferFromMemory buffer(s.data(), s.size());
|
|
|
|
buffer.readStrict(reinterpret_cast<char *>(&capability_flags), 4);
|
|
|
|
buffer.readStrict(reinterpret_cast<char *>(&max_packet_size), 4);
|
|
|
|
buffer.readStrict(reinterpret_cast<char *>(&character_set), 1);
|
2019-04-29 06:05:30 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-03-26 18:30:41 +00:00
|
|
|
class HandshakeResponse : public ReadPacket
|
|
|
|
{
|
2019-03-16 02:08:21 +00:00
|
|
|
public:
|
2019-07-01 05:58:31 +00:00
|
|
|
uint32_t capability_flags = 0;
|
|
|
|
uint32_t max_packet_size = 0;
|
|
|
|
uint8_t character_set = 0;
|
2019-03-26 18:30:41 +00:00
|
|
|
String username;
|
|
|
|
String auth_response;
|
|
|
|
String database;
|
|
|
|
String auth_plugin_name;
|
2019-07-01 05:58:31 +00:00
|
|
|
PacketMemoryTracker tracker;
|
2019-03-16 02:08:21 +00:00
|
|
|
|
2019-04-29 06:05:30 +00:00
|
|
|
HandshakeResponse() = default;
|
|
|
|
|
2019-07-01 05:58:31 +00:00
|
|
|
void readPayload(Vector && payload) override
|
2019-03-26 18:30:41 +00:00
|
|
|
{
|
2019-07-01 05:58:31 +00:00
|
|
|
std::cerr << PacketSender::packetToText(payload) << std::endl;
|
|
|
|
tracker.alloc(payload.size());
|
|
|
|
ReadBufferFromMemory buffer(payload.data(), payload.size());
|
2019-03-16 02:08:21 +00:00
|
|
|
|
2019-07-01 05:58:31 +00:00
|
|
|
buffer.readStrict(reinterpret_cast<char *>(&capability_flags), 4);
|
|
|
|
buffer.readStrict(reinterpret_cast<char *>(&max_packet_size), 4);
|
|
|
|
buffer.readStrict(reinterpret_cast<char *>(&character_set), 1);
|
|
|
|
buffer.ignore(23);
|
2019-03-16 02:08:21 +00:00
|
|
|
|
2019-07-01 05:58:31 +00:00
|
|
|
readNullTerminated(username, buffer);
|
2019-03-16 02:08:21 +00:00
|
|
|
|
2019-03-26 18:30:41 +00:00
|
|
|
if (capability_flags & CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA)
|
|
|
|
{
|
2019-07-01 05:58:31 +00:00
|
|
|
auto len = readLengthEncodedNumber(buffer);
|
2019-03-16 02:08:21 +00:00
|
|
|
auth_response.resize(len);
|
2019-07-01 05:58:31 +00:00
|
|
|
buffer.readStrict(auth_response.data(), len);
|
2019-03-26 18:30:41 +00:00
|
|
|
}
|
|
|
|
else if (capability_flags & CLIENT_SECURE_CONNECTION)
|
|
|
|
{
|
2019-07-01 05:58:31 +00:00
|
|
|
char len;
|
|
|
|
buffer.readStrict(len);
|
|
|
|
auth_response.resize(static_cast<unsigned int>(len));
|
|
|
|
buffer.readStrict(auth_response.data(), len);
|
2019-03-26 18:30:41 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-07-01 05:58:31 +00:00
|
|
|
readNullTerminated(auth_response, buffer);
|
2019-03-16 02:08:21 +00:00
|
|
|
}
|
|
|
|
|
2019-03-26 18:30:41 +00:00
|
|
|
if (capability_flags & CLIENT_CONNECT_WITH_DB)
|
|
|
|
{
|
2019-07-01 05:58:31 +00:00
|
|
|
readNullTerminated(database, buffer);
|
2019-03-16 02:08:21 +00:00
|
|
|
}
|
|
|
|
|
2019-03-26 18:30:41 +00:00
|
|
|
if (capability_flags & CLIENT_PLUGIN_AUTH)
|
|
|
|
{
|
2019-07-01 05:58:31 +00:00
|
|
|
readNullTerminated(auth_plugin_name, buffer);
|
2019-03-16 02:08:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-03-26 18:30:41 +00:00
|
|
|
class AuthSwitchRequest : public WritePacket
|
|
|
|
{
|
|
|
|
String plugin_name;
|
|
|
|
String auth_plugin_data;
|
|
|
|
public:
|
|
|
|
AuthSwitchRequest(String plugin_name, String auth_plugin_data)
|
|
|
|
: plugin_name(std::move(plugin_name)), auth_plugin_data(std::move(auth_plugin_data))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-07-01 05:58:31 +00:00
|
|
|
void writePayload(WriteBuffer & buffer) const override
|
2019-03-26 18:30:41 +00:00
|
|
|
{
|
2019-07-01 05:58:31 +00:00
|
|
|
buffer.write(0xfe);
|
|
|
|
writeNulTerminatedString(plugin_name, buffer);
|
|
|
|
writeString(auth_plugin_data, buffer);
|
|
|
|
std::cerr << auth_plugin_data.size() << std::endl;
|
2019-03-26 18:30:41 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-04-22 10:57:50 +00:00
|
|
|
class AuthSwitchResponse : public ReadPacket
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
String value;
|
2019-07-01 05:58:31 +00:00
|
|
|
PacketMemoryTracker tracker;
|
2019-04-22 10:57:50 +00:00
|
|
|
|
2019-07-01 05:58:31 +00:00
|
|
|
void readPayload(Vector && payload) override
|
2019-04-22 10:57:50 +00:00
|
|
|
{
|
2019-07-01 05:58:31 +00:00
|
|
|
tracker.alloc(payload.size());
|
|
|
|
value.assign(payload.data(), payload.size());
|
2019-04-22 10:57:50 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class AuthMoreData : public WritePacket
|
|
|
|
{
|
|
|
|
String data;
|
|
|
|
public:
|
2019-07-01 05:58:31 +00:00
|
|
|
explicit AuthMoreData(String data): data(std::move(data)) {}
|
2019-04-22 10:57:50 +00:00
|
|
|
|
2019-07-01 05:58:31 +00:00
|
|
|
void writePayload(WriteBuffer & buffer) const override
|
2019-04-22 10:57:50 +00:00
|
|
|
{
|
2019-07-01 05:58:31 +00:00
|
|
|
buffer.write(0x01);
|
|
|
|
writeString(data, buffer);
|
2019-04-22 10:57:50 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-03-26 18:30:41 +00:00
|
|
|
/// Packet with a single null-terminated string. Is used for clear text authentication.
|
|
|
|
class NullTerminatedString : public ReadPacket
|
|
|
|
{
|
|
|
|
public:
|
2019-07-01 05:58:31 +00:00
|
|
|
Vector value;
|
2019-03-26 18:30:41 +00:00
|
|
|
|
2019-07-01 05:58:31 +00:00
|
|
|
void readPayload(Vector && payload) override
|
2019-03-26 18:30:41 +00:00
|
|
|
{
|
2019-07-01 05:58:31 +00:00
|
|
|
if (payload.empty() || payload.back() != 0)
|
2019-03-26 18:30:41 +00:00
|
|
|
{
|
|
|
|
throw ProtocolError("String is not null terminated.", ErrorCodes::UNKNOWN_PACKET_FROM_CLIENT);
|
|
|
|
}
|
2019-07-01 05:58:31 +00:00
|
|
|
value = std::move(payload);
|
2019-03-26 18:30:41 +00:00
|
|
|
value.pop_back();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class OK_Packet : public WritePacket
|
|
|
|
{
|
2019-03-16 02:08:21 +00:00
|
|
|
uint8_t header;
|
|
|
|
uint32_t capabilities;
|
|
|
|
uint64_t affected_rows;
|
|
|
|
int16_t warnings = 0;
|
|
|
|
uint32_t status_flags;
|
2019-03-26 18:30:41 +00:00
|
|
|
String session_state_changes;
|
2019-05-16 05:36:08 +00:00
|
|
|
String info;
|
2019-03-16 02:08:21 +00:00
|
|
|
public:
|
2019-05-16 05:36:08 +00:00
|
|
|
OK_Packet(uint8_t header,
|
|
|
|
uint32_t capabilities,
|
|
|
|
uint64_t affected_rows,
|
|
|
|
uint32_t status_flags,
|
|
|
|
int16_t warnings,
|
|
|
|
String session_state_changes = "",
|
|
|
|
String info = "")
|
|
|
|
: header(header)
|
|
|
|
, capabilities(capabilities)
|
|
|
|
, affected_rows(affected_rows)
|
|
|
|
, warnings(warnings)
|
|
|
|
, status_flags(status_flags)
|
|
|
|
, session_state_changes(std::move(session_state_changes))
|
|
|
|
, info(info)
|
2019-03-16 02:08:21 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-07-01 05:58:31 +00:00
|
|
|
void writePayload(WriteBuffer & buffer) const override
|
2019-03-26 18:30:41 +00:00
|
|
|
{
|
2019-07-01 05:58:31 +00:00
|
|
|
buffer.write(header);
|
|
|
|
writeLengthEncodedNumber(affected_rows, buffer);
|
|
|
|
writeLengthEncodedNumber(0, buffer); /// last insert-id
|
2019-03-16 02:08:21 +00:00
|
|
|
|
2019-03-26 18:30:41 +00:00
|
|
|
if (capabilities & CLIENT_PROTOCOL_41)
|
|
|
|
{
|
2019-07-01 05:58:31 +00:00
|
|
|
buffer.write(reinterpret_cast<const char *>(&status_flags), 2);
|
|
|
|
buffer.write(reinterpret_cast<const char *>(&warnings), 2);
|
2019-03-26 18:30:41 +00:00
|
|
|
}
|
|
|
|
else if (capabilities & CLIENT_TRANSACTIONS)
|
|
|
|
{
|
2019-07-01 05:58:31 +00:00
|
|
|
buffer.write(reinterpret_cast<const char *>(&status_flags), 2);
|
2019-03-16 02:08:21 +00:00
|
|
|
}
|
|
|
|
|
2019-03-26 18:30:41 +00:00
|
|
|
if (capabilities & CLIENT_SESSION_TRACK)
|
|
|
|
{
|
2019-07-01 05:58:31 +00:00
|
|
|
writeLengthEncodedNumber(info.length(), buffer);
|
|
|
|
writeString(info, buffer);
|
2019-03-26 18:30:41 +00:00
|
|
|
if (status_flags & SERVER_SESSION_STATE_CHANGED)
|
|
|
|
{
|
2019-07-01 05:58:31 +00:00
|
|
|
writeLengthEncodedNumber(session_state_changes.length(), buffer);
|
|
|
|
writeString(session_state_changes, buffer);
|
2019-03-16 02:08:21 +00:00
|
|
|
}
|
2019-03-26 18:30:41 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-07-01 05:58:31 +00:00
|
|
|
writeString(info, buffer);
|
2019-03-16 02:08:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-03-26 18:30:41 +00:00
|
|
|
class EOF_Packet : public WritePacket
|
|
|
|
{
|
2019-03-16 02:08:21 +00:00
|
|
|
int warnings;
|
|
|
|
int status_flags;
|
|
|
|
public:
|
2019-03-26 18:30:41 +00:00
|
|
|
EOF_Packet(int warnings, int status_flags) : warnings(warnings), status_flags(status_flags)
|
|
|
|
{}
|
2019-03-16 02:08:21 +00:00
|
|
|
|
2019-07-01 05:58:31 +00:00
|
|
|
void writePayload(WriteBuffer & buffer) const override
|
2019-03-26 18:30:41 +00:00
|
|
|
{
|
2019-07-01 05:58:31 +00:00
|
|
|
buffer.write(0xfe); // EOF header
|
|
|
|
buffer.write(reinterpret_cast<const char *>(&warnings), 2);
|
|
|
|
buffer.write(reinterpret_cast<const char *>(&status_flags), 2);
|
2019-03-16 02:08:21 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-03-26 18:30:41 +00:00
|
|
|
class ERR_Packet : public WritePacket
|
|
|
|
{
|
2019-03-16 02:08:21 +00:00
|
|
|
int error_code;
|
2019-03-26 18:30:41 +00:00
|
|
|
String sql_state;
|
|
|
|
String error_message;
|
2019-03-16 02:08:21 +00:00
|
|
|
public:
|
2019-03-26 18:30:41 +00:00
|
|
|
ERR_Packet(int error_code, String sql_state, String error_message)
|
|
|
|
: error_code(error_code), sql_state(std::move(sql_state)), error_message(std::move(error_message))
|
2019-03-16 02:08:21 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-07-01 05:58:31 +00:00
|
|
|
void writePayload(WriteBuffer & buffer) const override
|
2019-03-16 02:08:21 +00:00
|
|
|
{
|
2019-07-01 05:58:31 +00:00
|
|
|
buffer.write(0xff);
|
|
|
|
buffer.write(reinterpret_cast<const char *>(&error_code), 2);
|
|
|
|
buffer.write('#');
|
|
|
|
buffer.write(sql_state.data(), sql_state.length());
|
|
|
|
buffer.write(error_message.data(), std::min(error_message.length(), MYSQL_ERRMSG_SIZE));
|
2019-03-16 02:08:21 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-03-26 18:30:41 +00:00
|
|
|
class ColumnDefinition : public WritePacket
|
|
|
|
{
|
|
|
|
String schema;
|
|
|
|
String table;
|
|
|
|
String org_table;
|
|
|
|
String name;
|
|
|
|
String org_name;
|
2019-03-16 02:08:21 +00:00
|
|
|
size_t next_length = 0x0c;
|
|
|
|
uint16_t character_set;
|
|
|
|
uint32_t column_length;
|
|
|
|
ColumnType column_type;
|
|
|
|
uint16_t flags;
|
|
|
|
uint8_t decimals = 0x00;
|
|
|
|
public:
|
2019-03-26 18:30:41 +00:00
|
|
|
ColumnDefinition(
|
|
|
|
String schema,
|
|
|
|
String table,
|
|
|
|
String org_table,
|
|
|
|
String name,
|
|
|
|
String org_name,
|
2019-03-16 02:08:21 +00:00
|
|
|
uint16_t character_set,
|
|
|
|
uint32_t column_length,
|
|
|
|
ColumnType column_type,
|
|
|
|
uint16_t flags,
|
|
|
|
uint8_t decimals)
|
|
|
|
|
2019-03-26 18:30:41 +00:00
|
|
|
: schema(std::move(schema)), table(std::move(table)), org_table(std::move(org_table)), name(std::move(name)),
|
|
|
|
org_name(std::move(org_name)), character_set(character_set), column_length(column_length), column_type(column_type), flags(flags),
|
|
|
|
decimals(decimals)
|
2019-03-16 02:08:21 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-03-26 18:30:41 +00:00
|
|
|
/// Should be used when column metadata (original name, table, original table, database) is unknown.
|
|
|
|
ColumnDefinition(
|
|
|
|
String name,
|
|
|
|
uint16_t character_set,
|
|
|
|
uint32_t column_length,
|
|
|
|
ColumnType column_type,
|
|
|
|
uint16_t flags,
|
|
|
|
uint8_t decimals)
|
|
|
|
: ColumnDefinition("", "", "", std::move(name), "", character_set, column_length, column_type, flags, decimals)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-07-01 05:58:31 +00:00
|
|
|
void writePayload(WriteBuffer & buffer) const override
|
2019-03-26 18:30:41 +00:00
|
|
|
{
|
2019-07-01 05:58:31 +00:00
|
|
|
writeLengthEncodedString(std::string("def"), buffer); /// always "def"
|
|
|
|
writeLengthEncodedString(schema, buffer);
|
|
|
|
writeLengthEncodedString(table, buffer);
|
|
|
|
writeLengthEncodedString(org_table, buffer);
|
|
|
|
writeLengthEncodedString(name, buffer);
|
|
|
|
writeLengthEncodedString(org_name, buffer);
|
|
|
|
writeLengthEncodedNumber(next_length, buffer);
|
|
|
|
buffer.write(reinterpret_cast<const char *>(&character_set), 2);
|
|
|
|
buffer.write(reinterpret_cast<const char *>(&column_length), 4);
|
|
|
|
buffer.write(reinterpret_cast<const char *>(&column_type), 1);
|
|
|
|
buffer.write(reinterpret_cast<const char *>(&flags), 2);
|
|
|
|
buffer.write(reinterpret_cast<const char *>(&decimals), 2);
|
|
|
|
writeChar(0x0, 2, buffer);
|
2019-03-16 02:08:21 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-03-26 18:30:41 +00:00
|
|
|
class ComFieldList : public ReadPacket
|
|
|
|
{
|
2019-03-16 02:08:21 +00:00
|
|
|
public:
|
2019-03-26 18:30:41 +00:00
|
|
|
String table, field_wildcard;
|
2019-03-16 02:08:21 +00:00
|
|
|
|
2019-07-01 05:58:31 +00:00
|
|
|
void readPayload(Vector && payload) override
|
2019-03-16 02:08:21 +00:00
|
|
|
{
|
2019-07-01 05:58:31 +00:00
|
|
|
ReadBufferFromMemory buffer(payload.data(), payload.size());
|
|
|
|
buffer.ignore(1); // command byte
|
|
|
|
readNullTerminated(table, buffer);
|
|
|
|
field_wildcard.assign(payload.data() + table.size() + 2);
|
|
|
|
readStringUntilEOFInto(field_wildcard, buffer);
|
2019-03-16 02:08:21 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-03-26 18:30:41 +00:00
|
|
|
class LengthEncodedNumber : public WritePacket
|
|
|
|
{
|
|
|
|
uint64_t value;
|
|
|
|
public:
|
|
|
|
LengthEncodedNumber(uint64_t value): value(value)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-07-01 05:58:31 +00:00
|
|
|
void writePayload(WriteBuffer & buffer) const override
|
2019-03-26 18:30:41 +00:00
|
|
|
{
|
2019-07-01 05:58:31 +00:00
|
|
|
writeLengthEncodedNumber(value, buffer);
|
2019-03-26 18:30:41 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class ResultsetRow : public WritePacket
|
|
|
|
{
|
2019-07-01 05:58:31 +00:00
|
|
|
std::vector<Vector> columns;
|
2019-03-26 18:30:41 +00:00
|
|
|
public:
|
|
|
|
ResultsetRow()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-07-01 05:58:31 +00:00
|
|
|
void appendColumn(Vector value)
|
2019-03-26 18:30:41 +00:00
|
|
|
{
|
|
|
|
columns.emplace_back(std::move(value));
|
|
|
|
}
|
|
|
|
|
2019-07-01 05:58:31 +00:00
|
|
|
void writePayload(WriteBuffer & buffer) const override
|
2019-03-26 18:30:41 +00:00
|
|
|
{
|
2019-07-01 05:58:31 +00:00
|
|
|
for (const Vector & column : columns)
|
|
|
|
writeLengthEncodedString(column, buffer);
|
2019-03-26 18:30:41 +00:00
|
|
|
}
|
|
|
|
};
|
2019-03-16 02:08:21 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
}
|