// Copyright 2022 Memgraph Ltd. // // Use of this software is governed by the Business Source License // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source // License, and you may not use this file except in compliance with the Business Source License. // // As of the Change Date specified in that file, in accordance with // the Business Source License, use of this software will be governed // by the Apache License, Version 2.0, included in the file // licenses/APL.txt. #pragma once #include #include "communication/bolt/v1/codes.hpp" #include "communication/bolt/v1/state.hpp" #include "communication/bolt/v1/states/handlers.hpp" #include "communication/bolt/v1/value.hpp" #include "utils/cast.hpp" #include "utils/likely.hpp" #include "utils/logging.hpp" namespace memgraph::communication::bolt { /** * Error state run function * This function handles a Bolt session when it is in an error state. * The error state is exited upon receiving an ACK_FAILURE or RESET message. * @param session the session that should be used for the run */ template State StateErrorRun(TSession &session, State state) { Marker marker{}; Signature signature{}; if (!session.decoder_.ReadMessageHeader(&signature, &marker)) { spdlog::trace("Missing header data!"); return State::Close; } if (UNLIKELY(signature == Signature::Noop && session.version_.major == 4 && session.version_.minor == 1)) { spdlog::trace("Received NOOP message"); return state; } // Clear the data buffer if it has any leftover data. session.encoder_buffer_.Clear(); if (session.version_.major == 1 && signature == Signature::AckFailure) { spdlog::trace("AckFailure received"); if (!session.encoder_.MessageSuccess()) { spdlog::trace("Couldn't send success message!"); return State::Close; } // We got AckFailure get back to right state. MG_ASSERT(state == State::Error, "Shouldn't happen"); return State::Idle; } if (signature == Signature::Reset) { spdlog::trace("Reset received"); return HandleReset(session, marker); } uint8_t value = utils::UnderlyingCast(marker); // All bolt client messages have less than 15 parameters so if we receive // anything than a TinyStruct it's an error. if ((value & 0xF0U) != utils::UnderlyingCast(Marker::TinyStruct)) { spdlog::trace("Expected TinyStruct marker, but received 0x{:02X}!", value); return State::Close; } // We need to clean up all parameters from this command. value &= 0x0FU; // The length is stored in the lower nibble. Value dv; for (int i = 0; i < value; ++i) { if (!session.decoder_.ReadValue(&dv)) { spdlog::trace("Couldn't clean up parameter {} / {}!", i, value); return State::Close; } } // Ignore this message. if (!session.encoder_.MessageIgnored()) { spdlog::trace("Couldn't send ignored message!"); return State::Close; } // Cleanup done, command ignored, stay in error state. return state; } } // namespace memgraph::communication::bolt