Files
scylladb/cql/binary.rl
Pekka Enberg 2a7da21481 CQL binary protocol
This patch implement initial support for CQL binary protocol versions 1,
2, 3, and 4. The CQL server is able to handshake with cqlsh and
cassandra-stress from Cassandra 2.1 which uses the STARTUP and OPTIONS
messages. Queries or other functionality is not supported.

To try it out, start Urchin:

  $ build/release/seastar --smp 1 --datadir data
  CQL server listening on port 9042 ...
  Thrift server listening on port 9160 ...

Then try to login with cqlsh:

  $ ./bin/cqlsh 127.0.0.1

Urchin side will fail with:

  CQL_VERSION => 3.2.0
  warning: ignoring event registration
  warning: ignoring query SELECT peer, data_center, rack, tokens, rpc_address, schema_version FROM system.peers
  seastar: cql/server.cc:222: future<> cql_server::connection::process_query(uint16_t, temporary_buffer<char>&): Assertion `0' failed.
  Aborted (core dumped)

TODO:

  - Compression is not supported.

  - Authentication is not supported.

  - Supported options are defined to make cqlsh and cassandra-stress
    happy. We really need to decide which CQL versions and compression
    algorithms we want to support.

  - std::string is used everywhere because sstring does not work with
    std::map, std::multimap, and others.

Signed-off-by: Pekka Enberg <penberg@cloudius-systems.com>
Signed-off-by: Tomasz Grabiec <tgrabiec@cloudius-systems.com>
2015-02-02 19:28:31 +01:00

149 lines
3.7 KiB
Ragel
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Copyright (C) 2015 Cloudius Systems, Ltd.
*/
#include "core/ragel.hh"
#include <algorithm>
/*
* CQL binary protocol versions [1234]
*/
%%{
machine cql_binary_protocol;
access _fsm_;
action mark {
_g = p;
}
v1 = 0x01 >mark @{ _version = read_u8(); };
v2 = 0x02 >mark @{ _version = read_u8(); };
v3 = 0x03 >mark @{ _version = read_u8(); };
v4 = 0x04 >mark @{ _version = read_u8(); };
v1_v2 = v1|v2;
v3_v4 = v3|v4;
flags = any{1} >mark @{ _flags = read_u8(); };
stream8 = any{1} >mark @{ _stream = read_u8(); };
stream16 = any{2} >mark @{ _stream = read_be16(); };
length = any{4} >mark @{ _length = read_be32(); };
startup_v1_v2 = v1_v2 flags stream8 0x01 length @{ _state = state::req_startup; };
credentials_v1 = v1 flags stream8 0x04 length @{ _state = state::req_credentials; };
auth_response_v2 = v2 flags stream8 0x0f length @{ _state = state::req_auth_response; };
options_v1_v2 = v1_v2 flags stream8 0x05 length @{ _state = state::req_options; };
query_v1_v2 = v1_v2 flags stream8 0x07 length @{ _state = state::req_query; };
prepare_v1_v2 = v1_v2 flags stream8 0x09 length @{ _state = state::req_prepare; };
execute_v1_v2 = v1_v2 flags stream8 0x0a length @{ _state = state::req_execute; };
batch_v1_v2 = v1_v2 flags stream8 0x0d length @{ _state = state::req_batch; };
register_v1_v2 = v1_v2 flags stream8 0x0b length @{ _state = state::req_register; };
request_v1_v2 = startup_v1_v2|credentials_v1|auth_response_v2|options_v1_v2|query_v1_v2|prepare_v1_v2|execute_v1_v2|batch_v1_v2|register_v1_v2;
startup_v3_v4 = v3_v4 flags stream16 0x01 length @{ _state = state::req_startup; };
auth_response_v3_v4 = v3_v4 flags stream16 0x0f length @{ _state = state::req_auth_response; };
options_v3_v4 = v3_v4 flags stream16 0x05 length @{ _state = state::req_options; };
query_v3_v4 = v3_v4 flags stream16 0x07 length @{ _state = state::req_query; };
prepare_v3_v4 = v3_v4 flags stream16 0x09 length @{ _state = state::req_prepare; };
execute_v3_v4 = v3_v4 flags stream16 0x0a length @{ _state = state::req_execute; };
batch_v3_v4 = v3_v4 flags stream16 0x0d length @{ _state = state::req_batch; };
register_v3_v4 = v3_v4 flags stream16 0x0b length @{ _state = state::req_register; };
request_v3_v4 = startup_v3_v4|auth_response_v3_v4|options_v3_v4|query_v3_v4|prepare_v3_v4|execute_v3_v4|batch_v3_v4|register_v3_v4;
main := request_v1_v2|request_v3_v4 @eof{ _state = state::eof; };
prepush {
prepush();
}
postpop {
postpop();
}
}%%
class cql_binary_parser : public ragel_parser_base<cql_binary_parser> {
%% write data nofinal noprefix;
public:
enum class state {
error,
eof,
req_startup,
req_credentials,
req_auth_response,
req_options,
req_query,
req_prepare,
req_execute,
req_batch,
req_register,
};
state _state;
int8_t _version;
int8_t _flags;
int16_t _stream;
int32_t _length;
char* _g;
public:
void init() {
init_base();
_state = state::error;
%% write init;
}
char* parse(char* p, char* pe, char* eof) {
%% write exec;
if (_state != state::error) {
return p;
}
if (p != pe) {
p = pe;
return p;
}
return nullptr;
}
uint8_t read_u8() {
return _g[0];
}
uint16_t read_be16() {
return (static_cast<uint8_t>(_g[0]) << 8)
| (static_cast<uint8_t>(_g[1]));
}
uint32_t read_be32() {
return (static_cast<uint8_t>(_g[0]) << 24)
| (static_cast<uint8_t>(_g[1]) << 16)
| (static_cast<uint8_t>(_g[2]) << 8)
| (static_cast<uint8_t>(_g[3]));
}
bool eof() const {
return _state == state::eof;
}
};