in src/commands/cmd_server.cc [723:811]
Status Execute([[maybe_unused]] engine::Context &ctx, Server *srv, Connection *conn, std::string *output) override {
size_t next_arg = 1;
int protocol = 2; // default protocol version is 2
if (args_.size() >= 2) {
auto parse_result = ParseInt<int>(args_[next_arg], 10);
++next_arg;
if (!parse_result) {
return {Status::NotOK, "Protocol version is not an integer or out of range"};
}
protocol = *parse_result;
// In redis, it will check protocol < 2 or protocol > 3,
// kvrocks only supports REPL2 by now, but for supporting some
// `hello 3`, it will not report error when using 3.
if (protocol < 2 || protocol > 3) {
return {Status::RedisNoProto, "unsupported protocol version"};
}
}
// Handling AUTH and SETNAME
for (; next_arg < args_.size(); ++next_arg) {
size_t more_args = args_.size() - next_arg - 1;
const std::string &opt = args_[next_arg];
if (util::ToLower(opt) == "auth" && more_args != 0) {
if (more_args == 2 || more_args == 4) {
if (args_[next_arg + 1] != "default") {
return {Status::NotOK, "Invalid password"};
}
next_arg++;
}
const auto &user_password = args_[next_arg + 1];
std::string ns;
AuthResult auth_result = srv->AuthenticateUser(user_password, &ns);
switch (auth_result) {
case AuthResult::NO_REQUIRE_PASS:
return {Status::NotOK, "Client sent AUTH, but no password is set"};
case AuthResult::INVALID_PASSWORD:
return {Status::NotOK, "Invalid password"};
case AuthResult::IS_USER:
conn->BecomeUser();
break;
case AuthResult::IS_ADMIN:
conn->BecomeAdmin();
break;
}
conn->SetNamespace(ns);
next_arg += 1;
} else if (util::ToLower(opt) == "setname" && more_args != 0) {
const std::string &name = args_[next_arg + 1];
conn->SetName(name);
next_arg += 1;
} else {
return {Status::RedisExecErr, "Syntax error in HELLO option " + opt};
}
}
std::vector<std::string> output_list;
output_list.push_back(redis::BulkString("server"));
output_list.push_back(redis::BulkString("redis"));
output_list.push_back(redis::BulkString("version"));
// What the client want is the Redis compatible version instead of the Kvrocks version.
output_list.push_back(redis::BulkString(REDIS_VERSION));
output_list.push_back(redis::BulkString("proto"));
if (srv->GetConfig()->resp3_enabled) {
output_list.push_back(redis::Integer(protocol));
conn->SetProtocolVersion(protocol == 3 ? RESP::v3 : RESP::v2);
} else {
output_list.push_back(redis::Integer(2));
}
output_list.push_back(redis::BulkString("mode"));
// Note: sentinel is not supported in kvrocks.
if (srv->GetConfig()->cluster_enabled) {
output_list.push_back(redis::BulkString("cluster"));
} else {
output_list.push_back(redis::BulkString("standalone"));
}
output_list.push_back(redis::BulkString("role"));
output_list.push_back(redis::BulkString(srv->IsSlave() ? "slave" : "master"));
// For Kvrocks, the modules is not supported.
output_list.push_back(redis::BulkString("modules"));
output_list.push_back(conn->NilArray());
*output = conn->HeaderOfMap(output_list.size() / 2);
for (const auto &item : output_list) {
*output += item;
}
return Status::OK();
}