<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

// NOTE: This file is intended to be customised by the end user, and includes
// only local node policy logic

#include <policy/policy.h>

#include <script/interpreter.h>
#include <tinyformat.h>
#include <util/strencodings.h>
#include <util/system.h>
#include <validation.h>

Amount GetDustThreshold(const CTxOut &txout, const CFeeRate &dustRelayFeeIn) {
    /**
     * "Dust" is defined in terms of dustRelayFee, which has units
     * satoshis-per-kilobyte. If you'd pay more than 1/3 in fees to spend
     * something, then we consider it dust.  A typical spendable txout is 34
     * bytes big, and will need a CTxIn of at least 148 bytes to spend: so dust
     * is a spendable txout less than 546*dustRelayFee/1000 (in satoshis).
     */
    if (txout.scriptPubKey.IsUnspendable()) {
        return Amount::zero();
    }

    size_t nSize = GetSerializeSize(txout);

    // the 148 mentioned above
    nSize += (32 + 4 + 1 + 107 + 4);

    return 3 * dustRelayFeeIn.GetFee(nSize);
}

bool IsDust(const CTxOut &txout, const CFeeRate &dustRelayFeeIn) {
    return (txout.nValue < GetDustThreshold(txout, dustRelayFeeIn));
}

bool IsStandard(const CScript &scriptPubKey, txnouttype &whichType) {
    std::vector<std::vector<uint8_t>> vSolutions;
    if (!Solver(scriptPubKey, whichType, vSolutions)) {
        return false;
    }

    if (whichType == TX_MULTISIG) {
        uint8_t m = vSolutions.front()[0];
        uint8_t n = vSolutions.back()[0];
        // Support up to x-of-3 multisig txns as standard
        if (n < 1 || n > 3) return false;
        if (m < 1 || m > n) return false;
    } else if (whichType == TX_NULL_DATA) {
        if (!fAcceptDatacarrier) {
            return false;
        }

        unsigned nMaxDatacarrierBytes =
            gArgs.GetArg("-datacarriersize", MAX_OP_RETURN_RELAY);
        if (scriptPubKey.size() > nMaxDatacarrierBytes) {
            return false;
        }
    }

    return whichType != TX_NONSTANDARD;
}

bool IsStandardTx(const CTransaction &tx, std::string &reason) {
    if (tx.nVersion > CTransaction::MAX_STANDARD_VERSION || tx.nVersion < 1) {
        reason = "version";
        return false;
    }

    // Extremely large transactions with lots of inputs can cost the network
    // almost as much to process as they cost the sender in fees, because
    // computing signature hashes is O(ninputs*txsize). Limiting transactions
    // to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks.
    uint32_t sz = tx.GetTotalSize();
    if (sz >= MAX_STANDARD_TX_SIZE) {
        reason = "tx-size";
        return false;
    }

    for (const CTxIn &txin : tx.vin) {
        if (txin.scriptSig.size() > MAX_TX_IN_SCRIPT_SIG_SIZE) {
            reason = "scriptsig-size";
            return false;
        }
        if (!txin.scriptSig.IsPushOnly()) {
            reason = "scriptsig-not-pushonly";
            return false;
        }
    }

    unsigned int nDataOut = 0;
    txnouttype whichType;
    for (const CTxOut &txout : tx.vout) {
        if (!::IsStandard(txout.scriptPubKey, whichType)) {
            reason = "scriptpubkey";
            return false;
        }

        if (whichType == TX_NULL_DATA) {
            nDataOut++;
        } else if ((whichType == TX_MULTISIG) && (!fIsBareMultisigStd)) {
            reason = "bare-multisig";
            return false;
        } else if (IsDust(txout, ::dustRelayFee)) {
            reason = "dust";
            return false;
        }
    }

    // only one OP_RETURN txout is permitted
    if (nDataOut > 1) {
        reason = "multi-op-return";
        return false;
    }

    return true;
}

/**
 * Check transaction inputs to mitigate two
 * potential denial-of-service attacks:
 *
 * 1. scriptSigs with extra data stuffed into them,
 *    not consumed by scriptPubKey (or P2SH script)
 * 2. P2SH scripts with a crazy number of expensive
 *    CHECKSIG/CHECKMULTISIG operations
 *
 * Why bother? To avoid denial-of-service attacks; an attacker
 * can submit a standard HASH... OP_EQUAL transaction,
 * which will get accepted into blocks. The redemption
 * script can be anything; an attacker could use a very
 * expensive-to-check-upon-redemption script like:
 *   DUP CHECKSIG DROP ... repeated 100 times... OP_1
 */
bool AreInputsStandard(const CTransaction &tx,
                       const CCoinsViewCache &mapInputs) {
    if (tx.IsCoinBase()) {
        // Coinbases don't use vin normally.
        return true;
    }

    for (const CTxIn &in : tx.vin) {
        const CTxOut &prev = mapInputs.GetOutputFor(in);

        std::vector<std::vector<uint8_t>> vSolutions;
        txnouttype whichType;
        // get the scriptPubKey corresponding to this input:
        const CScript &prevScript = prev.scriptPubKey;
        if (!Solver(prevScript, whichType, vSolutions)) {
            return false;
        }

        if (whichType == TX_SCRIPTHASH) {
            std::vector<std::vector<uint8_t>> stack;
            // convert the scriptSig into a stack, so we can inspect the
            // redeemScript
            if (!EvalScript(stack, in.scriptSig, SCRIPT_VERIFY_NONE,
                            BaseSignatureChecker())) {
                return false;
            }
            if (stack.empty()) {
                return false;
            }

            CScript subscript(stack.back().begin(), stack.back().end());
            if (subscript.GetSigOpCount(STANDARD_SCRIPT_VERIFY_FLAGS, true) >
                MAX_P2SH_SIGOPS) {
                return false;
            }
        }
    }

    return true;
}

CFeeRate dustRelayFee = CFeeRate(DUST_RELAY_TX_FEE);
uint32_t nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP;

int64_t GetVirtualTransactionSize(int64_t nSize, int64_t nSigOpCount,
                                  unsigned int bytes_per_sigop) {
    return std::max(nSize, nSigOpCount * bytes_per_sigop);
}

int64_t GetVirtualTransactionSize(const CTransaction &tx, int64_t nSigOpCount,
                                  unsigned int bytes_per_sigop) {
    return GetVirtualTransactionSize(::GetSerializeSize(tx, PROTOCOL_VERSION),
                                     nSigOpCount, bytes_per_sigop);
}

int64_t GetVirtualTransactionInputSize(const CTxIn &txin, int64_t nSigOpCount,
                                       unsigned int bytes_per_sigop) {
    return GetVirtualTransactionSize(::GetSerializeSize(txin, PROTOCOL_VERSION),
                                     nSigOpCount, bytes_per_sigop);
}
<commit_msg>Add some braces to policy/policy.cpp<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

// NOTE: This file is intended to be customised by the end user, and includes
// only local node policy logic

#include <policy/policy.h>

#include <script/interpreter.h>
#include <tinyformat.h>
#include <util/strencodings.h>
#include <util/system.h>
#include <validation.h>

Amount GetDustThreshold(const CTxOut &txout, const CFeeRate &dustRelayFeeIn) {
    /**
     * "Dust" is defined in terms of dustRelayFee, which has units
     * satoshis-per-kilobyte. If you'd pay more than 1/3 in fees to spend
     * something, then we consider it dust.  A typical spendable txout is 34
     * bytes big, and will need a CTxIn of at least 148 bytes to spend: so dust
     * is a spendable txout less than 546*dustRelayFee/1000 (in satoshis).
     */
    if (txout.scriptPubKey.IsUnspendable()) {
        return Amount::zero();
    }

    size_t nSize = GetSerializeSize(txout);

    // the 148 mentioned above
    nSize += (32 + 4 + 1 + 107 + 4);

    return 3 * dustRelayFeeIn.GetFee(nSize);
}

bool IsDust(const CTxOut &txout, const CFeeRate &dustRelayFeeIn) {
    return (txout.nValue < GetDustThreshold(txout, dustRelayFeeIn));
}

bool IsStandard(const CScript &scriptPubKey, txnouttype &whichType) {
    std::vector<std::vector<uint8_t>> vSolutions;
    if (!Solver(scriptPubKey, whichType, vSolutions)) {
        return false;
    }

    if (whichType == TX_MULTISIG) {
        uint8_t m = vSolutions.front()[0];
        uint8_t n = vSolutions.back()[0];
        // Support up to x-of-3 multisig txns as standard
        if (n < 1 || n > 3) {
            return false;
        }
        if (m < 1 || m > n) {
            return false;
        }
    } else if (whichType == TX_NULL_DATA) {
        if (!fAcceptDatacarrier) {
            return false;
        }

        unsigned nMaxDatacarrierBytes =
            gArgs.GetArg("-datacarriersize", MAX_OP_RETURN_RELAY);
        if (scriptPubKey.size() > nMaxDatacarrierBytes) {
            return false;
        }
    }

    return whichType != TX_NONSTANDARD;
}

bool IsStandardTx(const CTransaction &tx, std::string &reason) {
    if (tx.nVersion > CTransaction::MAX_STANDARD_VERSION || tx.nVersion < 1) {
        reason = "version";
        return false;
    }

    // Extremely large transactions with lots of inputs can cost the network
    // almost as much to process as they cost the sender in fees, because
    // computing signature hashes is O(ninputs*txsize). Limiting transactions
    // to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks.
    uint32_t sz = tx.GetTotalSize();
    if (sz >= MAX_STANDARD_TX_SIZE) {
        reason = "tx-size";
        return false;
    }

    for (const CTxIn &txin : tx.vin) {
        if (txin.scriptSig.size() > MAX_TX_IN_SCRIPT_SIG_SIZE) {
            reason = "scriptsig-size";
            return false;
        }
        if (!txin.scriptSig.IsPushOnly()) {
            reason = "scriptsig-not-pushonly";
            return false;
        }
    }

    unsigned int nDataOut = 0;
    txnouttype whichType;
    for (const CTxOut &txout : tx.vout) {
        if (!::IsStandard(txout.scriptPubKey, whichType)) {
            reason = "scriptpubkey";
            return false;
        }

        if (whichType == TX_NULL_DATA) {
            nDataOut++;
        } else if ((whichType == TX_MULTISIG) && (!fIsBareMultisigStd)) {
            reason = "bare-multisig";
            return false;
        } else if (IsDust(txout, ::dustRelayFee)) {
            reason = "dust";
            return false;
        }
    }

    // only one OP_RETURN txout is permitted
    if (nDataOut > 1) {
        reason = "multi-op-return";
        return false;
    }

    return true;
}

/**
 * Check transaction inputs to mitigate two
 * potential denial-of-service attacks:
 *
 * 1. scriptSigs with extra data stuffed into them,
 *    not consumed by scriptPubKey (or P2SH script)
 * 2. P2SH scripts with a crazy number of expensive
 *    CHECKSIG/CHECKMULTISIG operations
 *
 * Why bother? To avoid denial-of-service attacks; an attacker
 * can submit a standard HASH... OP_EQUAL transaction,
 * which will get accepted into blocks. The redemption
 * script can be anything; an attacker could use a very
 * expensive-to-check-upon-redemption script like:
 *   DUP CHECKSIG DROP ... repeated 100 times... OP_1
 */
bool AreInputsStandard(const CTransaction &tx,
                       const CCoinsViewCache &mapInputs) {
    if (tx.IsCoinBase()) {
        // Coinbases don't use vin normally.
        return true;
    }

    for (const CTxIn &in : tx.vin) {
        const CTxOut &prev = mapInputs.GetOutputFor(in);

        std::vector<std::vector<uint8_t>> vSolutions;
        txnouttype whichType;
        // get the scriptPubKey corresponding to this input:
        const CScript &prevScript = prev.scriptPubKey;
        if (!Solver(prevScript, whichType, vSolutions)) {
            return false;
        }

        if (whichType == TX_SCRIPTHASH) {
            std::vector<std::vector<uint8_t>> stack;
            // convert the scriptSig into a stack, so we can inspect the
            // redeemScript
            if (!EvalScript(stack, in.scriptSig, SCRIPT_VERIFY_NONE,
                            BaseSignatureChecker())) {
                return false;
            }
            if (stack.empty()) {
                return false;
            }

            CScript subscript(stack.back().begin(), stack.back().end());
            if (subscript.GetSigOpCount(STANDARD_SCRIPT_VERIFY_FLAGS, true) >
                MAX_P2SH_SIGOPS) {
                return false;
            }
        }
    }

    return true;
}

CFeeRate dustRelayFee = CFeeRate(DUST_RELAY_TX_FEE);
uint32_t nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP;

int64_t GetVirtualTransactionSize(int64_t nSize, int64_t nSigOpCount,
                                  unsigned int bytes_per_sigop) {
    return std::max(nSize, nSigOpCount * bytes_per_sigop);
}

int64_t GetVirtualTransactionSize(const CTransaction &tx, int64_t nSigOpCount,
                                  unsigned int bytes_per_sigop) {
    return GetVirtualTransactionSize(::GetSerializeSize(tx, PROTOCOL_VERSION),
                                     nSigOpCount, bytes_per_sigop);
}

int64_t GetVirtualTransactionInputSize(const CTxIn &txin, int64_t nSigOpCount,
                                       unsigned int bytes_per_sigop) {
    return GetVirtualTransactionSize(::GetSerializeSize(txin, PROTOCOL_VERSION),
                                     nSigOpCount, bytes_per_sigop);
}
<|endoftext|>


<commit_before>/*
 * File:   StateGameStarted.cpp
 * Author: maxence
 *
 * Created on 16 janvier 2015, 23:28
 */
#include "shared/network/MsgData.h"
#include "shared/network/MsgType.h"
#include "shared/network/MsgAction.h"

#include "client/ClientPlayer.h"
#include "client/ClientWorld.h"

#include "client/view/DetailsView.h"
#include "client/view/GlobalView.h"

#include "client/network/ClientNetwork.h"

#include "client/state/game/ClientStateGame.h"
#include "client/state/game/ClientStateGameStarted.h"
#include "client/network/Input.h"

ClientStateGameStarted::ClientStateGameStarted(ClientStateGame& manager, ClientNetwork& network, ClientPlayer& player, ClientWorld& world)
: State()
, m_manager(manager)
, m_network(network)
, m_player(player)
, m_world(world)
, m_followingCamera(true)
, m_zoomValue(1.0f) {
}

ClientStateGameStarted::~ClientStateGameStarted() {

}

void ClientStateGameStarted::initialize(void) {
}

void ClientStateGameStarted::release(void) {
}

void ClientStateGameStarted::activate(void) {
    std::cout << "[GameStarted][Activate]" << std::endl;
    m_globalView = new GlobalView(m_world.getHeightMap(), m_world.getWindMap(), m_world.getClientShip());
    m_detailsView = new DetailsView(m_world);
    m_mainGraphic = dynamic_cast<sf::Drawable*> (m_detailsView);
}

void ClientStateGameStarted::deactivate(void) {
    std::cout << "[GameStarted][Desactivate]" << std::endl;
    m_mainGraphic = nullptr;
    delete m_globalView;
    delete m_detailsView;
}

void ClientStateGameStarted::update(float dt) {
    Input input(m_keys, m_clock.getElapsedTime());

    m_world.update(dt);
    sf::Uint32 id = m_predictions.add(input);
    sendInfo(input, id);
}

void ClientStateGameStarted::render(sf::RenderWindow& window) const {

    // Set view position
    if (m_followingCamera) {
        m_detailsView->setCenter(m_world.getClientShip().getPosition());
    }

    // Draw view
    if (m_mainGraphic)
        window.draw(*m_mainGraphic);

    // Draw winnner
    /*if (m_endGame != nullptr) {
        window.setView(window.getDefaultView());
        window.draw(TextView(m_winner, 40, TypeAlign::Center));
    }*/
}

void ClientStateGameStarted::sendInfo(const Input &input, sf::Uint32 id) {
    MsgData msg;
    msg << MsgType::Action << static_cast<sf::Uint8> (input.getActions().to_ulong()) << id;
    m_network.getUdpManager().send(msg);
}

bool ClientStateGameStarted::switchFollowingCamera() {
    m_followingCamera = !m_followingCamera;
    return m_followingCamera;
}

bool ClientStateGameStarted::read(sf::Event& event) {

    if (event.type == sf::Event::Closed) {
        return false;
    } else if (event.type == sf::Event::Resized) {
        m_detailsView->getView().setSize({event.size.width * m_zoomValue, event.size.height * m_zoomValue});
    } else if (event.type == sf::Event::KeyPressed) {
        switch (event.key.code) {
            case sf::Keyboard::Left:
                m_detailsView->getView().move(-5.0f * m_zoomValue, 0.0f);
                break;
            case sf::Keyboard::Right:
                m_detailsView->getView().move(5.0f * m_zoomValue, 0.0f);
                break;
            case sf::Keyboard::Up:
                m_detailsView->getView().move(0.0f, -5.0f * m_zoomValue);
                break;
            case sf::Keyboard::Down:
                m_detailsView->getView().move(0.0f, 5.0f * m_zoomValue);
                break;

            case sf::Keyboard::L:
            case sf::Keyboard::Subtract:
                m_zoomValue *= 2.0f;
                m_detailsView->getView().zoom(2.0f);
                break;

            case sf::Keyboard::P:
            case sf::Keyboard::Add:
                m_zoomValue *= 0.5f;
                m_detailsView->getView().zoom(0.5f);
                break;
            case sf::Keyboard::D:
                m_world.getClientShip().setTurningPositive(true);
                m_keys.set(TURN_HELM_POSITIVE, true);
                break;
            case sf::Keyboard::Q:
                m_world.getClientShip().setTurningNegative(true);
                m_keys.set(TURN_HELM_NEGATIVE, true);
                break;
            case sf::Keyboard::Z:
                m_world.getClientShip().getSail().setTurningPositive(true);
                m_keys.set(TURN_SAIL_POSITIVE, true);
                break;
            case sf::Keyboard::S:
                m_world.getClientShip().getSail().setTurningNegative(true);
                m_keys.set(TURN_SAIL_NEGATIVE, true);
                break;
            case sf::Keyboard::A:
                m_detailsView->switchSquared();
                break;
            case sf::Keyboard::W:
                m_detailsView->switchEnableWind();
                break;
            case sf::Keyboard::C:
                switchFollowingCamera();
                break;
            case sf::Keyboard::M:
                m_mainGraphic = (m_mainGraphic == dynamic_cast<sf::Drawable*> (m_detailsView)) ? dynamic_cast<sf::Drawable*> (m_globalView) : dynamic_cast<sf::Drawable*> (m_detailsView);
                break;
            case sf::Keyboard::Escape:
                return false;
                break;
            default:
                break;
        }
    } else if (event.type == sf::Event::KeyReleased) {
        switch (event.key.code) {
            case sf::Keyboard::D:
                m_keys.set(TURN_HELM_POSITIVE, false);
                m_world.getClientShip().setTurningPositive(false);
                break;
            case sf::Keyboard::Q:
                m_keys.set(TURN_HELM_NEGATIVE, false);
                m_world.getClientShip().setTurningNegative(false);
                break;
            case sf::Keyboard::Z:
                m_keys.set(TURN_SAIL_POSITIVE, false);
                m_world.getClientShip().getSail().setTurningPositive(false);
                break;
            case sf::Keyboard::S:
                m_keys.set(TURN_SAIL_NEGATIVE, false);
                m_world.getClientShip().getSail().setTurningNegative(false);
                break;
            default:
                break;
        }
    }
    return true;
}

bool ClientStateGameStarted::read(MsgData& msg) {
    MsgType msgType;
    msg >> msgType;
    switch (msgType) {
        case MsgType::GameInfo:
            return readGameInfo(msg);
        case MsgType::Disconnect:
            return readDisconnect(msg);
        case MsgType::Checkpoint:
            return readCheckpoint(msg);
        case MsgType::GameEnd:
            return readMsgEnd(msg);
        default:
            return true;
    }
}

bool ClientStateGameStarted::readGameInfo(MsgData & msg) {
    std::cout << "GameInfo" << std::endl;
    sf::Uint32 idReq;
    msg >> idReq;

    while (!msg.endOfPacket()) {

        sf::Uint8 id;
        float shipAngle;
        float sailAngle;
        float positionX;
        float positionY;
        float speedX;
        float speedY;

        msg >> id >> shipAngle >> sailAngle >> positionX >> positionY >> speedX >> speedY;

        Ship &ship = m_world.getShips()[static_cast<unsigned int> (id)];
        ship.setAngle(shipAngle);
        ship.getSail().setAngle(sailAngle);
        ship.position() = {positionX, positionY};
        ship.velocity() = {speedX, speedY};
        std::cout << "Recv ship(" << static_cast<unsigned int> (id) << ") pos(" << positionX << "," << positionY << ") speed(" << speedX << "," << speedY << ")" << std::endl;
    }

    updatePrediction(idReq);
    return true;
}

void ClientStateGameStarted::updatePrediction(sf::Uint32 reqId) {
    std::vector<Input> predictions = m_predictions.getInputFrom(reqId);
    std::cout << "nbPrediction(" << predictions.size() << ")" << std::endl;
    Input* prevInput = &predictions[0];

    sf::Vector2f oldShipPos = m_world.getClientShip().getPosition();

    for (unsigned int i = 1; i < predictions.size(); ++i) {

        // Set state of world
        Ship& ship = m_world.getClientShip();
        ship.setTurningNegative(prevInput->getActions().test(TURN_HELM_NEGATIVE));
        ship.setTurningPositive(prevInput->getActions().test(TURN_HELM_POSITIVE));
        ship.getSail().setTurningNegative(prevInput->getActions().test(TURN_SAIL_NEGATIVE));
        ship.getSail().setTurningPositive(prevInput->getActions().test(TURN_SAIL_POSITIVE));

        // Update
        sf::Time diffTime = predictions[i].getTime() - prevInput->getTime();
        m_world.updateShip(m_world.getClientShip(), diffTime.asSeconds());

        // Go to the next predictions
        prevInput = &predictions[i];
    }

    // Set state of world
    Ship& ship = m_world.getClientShip();
    sf::Vector2f& newShipPos = ship.position();

    // Smouth correction
    sf::Vector2f diffPos = newShipPos - oldShipPos;
//    if(std::abs(diffPos.x) < 1) {
//        newShipPos.x =  oldShipPos.x + (diffPos.x * 0.2);
//    }
//    if(std::abs(diffPos.y) < 1) {
//        newShipPos.y =  oldShipPos.y + (diffPos.y * 0.2);
//    }

    ship.setTurningNegative(prevInput->getActions().test(TURN_HELM_NEGATIVE));
    ship.setTurningPositive(prevInput->getActions().test(TURN_HELM_POSITIVE));
    ship.getSail().setTurningNegative(prevInput->getActions().test(TURN_SAIL_NEGATIVE));
    ship.getSail().setTurningPositive(prevInput->getActions().test(TURN_SAIL_POSITIVE));

}

bool ClientStateGameStarted::readCheckpoint(MsgData& msg) {
    sf::Uint8 idCheckpoint;

    msg >> idCheckpoint;
    m_world.getCheckPointManager().getCheckPoint(idCheckpoint).activate();
    return true;
}

bool ClientStateGameStarted::readDisconnect(MsgData & msg) {
    sf::Uint8 id;
    msg >> id;
    std::cout << m_world.getShips().erase(static_cast<unsigned int> (id)) << std::endl;
    m_detailsView->updateShips();
    std::cout << "Ship of player " << static_cast<unsigned int> (id) << " remove and view update" << std::endl;
    return true;
}

bool ClientStateGameStarted::readMsgEnd(MsgData & msg) {
    m_manager.push(EStateGame::End);
    return true;
}<commit_msg>add missing add<commit_after>/*
 * File:   StateGameStarted.cpp
 * Author: maxence
 *
 * Created on 16 janvier 2015, 23:28
 */
#include "shared/network/MsgData.h"
#include "shared/network/MsgType.h"
#include "shared/network/MsgAction.h"

#include "client/ClientPlayer.h"
#include "client/ClientWorld.h"

#include "client/view/DetailsView.h"
#include "client/view/GlobalView.h"

#include "client/network/ClientNetwork.h"

#include "client/state/game/ClientStateGame.h"
#include "client/state/game/ClientStateGameStarted.h"
#include "client/network/Input.h"

ClientStateGameStarted::ClientStateGameStarted(ClientStateGame& manager, ClientNetwork& network, ClientPlayer& player, ClientWorld& world)
: State()
, m_manager(manager)
, m_network(network)
, m_player(player)
, m_world(world)
, m_followingCamera(true)
, m_zoomValue(1.0f) {
}

ClientStateGameStarted::~ClientStateGameStarted() {

}

void ClientStateGameStarted::initialize(void) {
}

void ClientStateGameStarted::release(void) {
}

void ClientStateGameStarted::activate(void) {
    std::cout << "[GameStarted][Activate]" << std::endl;
    m_globalView = new GlobalView(m_world.getHeightMap(), m_world.getWindMap(), m_world.getClientShip());
    m_detailsView = new DetailsView(m_world);
    m_mainGraphic = dynamic_cast<sf::Drawable*> (m_detailsView);
}

void ClientStateGameStarted::deactivate(void) {
    std::cout << "[GameStarted][Desactivate]" << std::endl;
    m_mainGraphic = nullptr;
    delete m_globalView;
    delete m_detailsView;
}

void ClientStateGameStarted::update(float dt) {
    Input input(m_keys, m_clock.getElapsedTime());

    m_world.update(dt);
    sf::Uint32 id = m_predictions.add(input);
    sendInfo(input, id);
}

void ClientStateGameStarted::render(sf::RenderWindow& window) const {

    // Set view position
    if (m_followingCamera) {
        m_detailsView->setCenter(m_world.getClientShip().getPosition());
    }

    // Draw view
    if (m_mainGraphic)
        window.draw(*m_mainGraphic);

    // Draw winnner
    /*if (m_endGame != nullptr) {
        window.setView(window.getDefaultView());
        window.draw(TextView(m_winner, 40, TypeAlign::Center));
    }*/
}

void ClientStateGameStarted::sendInfo(const Input &input, sf::Uint32 id) {
    MsgData msg;
    msg << MsgType::Action << static_cast<sf::Uint8> (input.getActions().to_ulong()) << id;
    m_network.getUdpManager().send(msg);
}

bool ClientStateGameStarted::switchFollowingCamera() {
    m_followingCamera = !m_followingCamera;
    return m_followingCamera;
}

bool ClientStateGameStarted::read(sf::Event& event) {

    if (event.type == sf::Event::Closed) {
        return false;
    } else if (event.type == sf::Event::Resized) {
        m_detailsView->getView().setSize({event.size.width * m_zoomValue, event.size.height * m_zoomValue});
    } else if (event.type == sf::Event::KeyPressed) {
        switch (event.key.code) {
            case sf::Keyboard::Left:
                m_detailsView->getView().move(-5.0f * m_zoomValue, 0.0f);
                break;
            case sf::Keyboard::Right:
                m_detailsView->getView().move(5.0f * m_zoomValue, 0.0f);
                break;
            case sf::Keyboard::Up:
                m_detailsView->getView().move(0.0f, -5.0f * m_zoomValue);
                break;
            case sf::Keyboard::Down:
                m_detailsView->getView().move(0.0f, 5.0f * m_zoomValue);
                break;

            case sf::Keyboard::L:
            case sf::Keyboard::Subtract:
                m_zoomValue *= 2.0f;
                m_detailsView->getView().zoom(2.0f);
                break;

            case sf::Keyboard::P:
            case sf::Keyboard::Add:
                m_zoomValue *= 0.5f;
                m_detailsView->getView().zoom(0.5f);
                break;
            case sf::Keyboard::D:
                m_world.getClientShip().setTurningPositive(true);
                m_keys.set(TURN_HELM_POSITIVE, true);
                break;
            case sf::Keyboard::Q:
                m_world.getClientShip().setTurningNegative(true);
                m_keys.set(TURN_HELM_NEGATIVE, true);
                break;
            case sf::Keyboard::Z:
                m_world.getClientShip().getSail().setTurningPositive(true);
                m_keys.set(TURN_SAIL_POSITIVE, true);
                break;
            case sf::Keyboard::S:
                m_world.getClientShip().getSail().setTurningNegative(true);
                m_keys.set(TURN_SAIL_NEGATIVE, true);
                break;
            case sf::Keyboard::A:
                m_detailsView->switchSquared();
                break;
            case sf::Keyboard::W:
                m_detailsView->switchEnableWind();
                break;
            case sf::Keyboard::C:
                switchFollowingCamera();
                break;
            case sf::Keyboard::M:
                m_mainGraphic = (m_mainGraphic == dynamic_cast<sf::Drawable*> (m_detailsView)) ? dynamic_cast<sf::Drawable*> (m_globalView) : dynamic_cast<sf::Drawable*> (m_detailsView);
                break;
            case sf::Keyboard::Escape:
                return false;
                break;
            default:
                break;
        }
    } else if (event.type == sf::Event::KeyReleased) {
        switch (event.key.code) {
            case sf::Keyboard::D:
                m_keys.set(TURN_HELM_POSITIVE, false);
                m_world.getClientShip().setTurningPositive(false);
                break;
            case sf::Keyboard::Q:
                m_keys.set(TURN_HELM_NEGATIVE, false);
                m_world.getClientShip().setTurningNegative(false);
                break;
            case sf::Keyboard::Z:
                m_keys.set(TURN_SAIL_POSITIVE, false);
                m_world.getClientShip().getSail().setTurningPositive(false);
                break;
            case sf::Keyboard::S:
                m_keys.set(TURN_SAIL_NEGATIVE, false);
                m_world.getClientShip().getSail().setTurningNegative(false);
                break;
            default:
                break;
        }
    }
    return true;
}

bool ClientStateGameStarted::read(MsgData& msg) {
    MsgType msgType;
    msg >> msgType;
    switch (msgType) {
        case MsgType::GameInfo:
            return readGameInfo(msg);
        case MsgType::Disconnect:
            return readDisconnect(msg);
        case MsgType::Checkpoint:
            return readCheckpoint(msg);
        case MsgType::GameEnd:
            return readMsgEnd(msg);
        default:
            return true;
    }
}

bool ClientStateGameStarted::readGameInfo(MsgData & msg) {
    std::cout << "GameInfo" << std::endl;
    sf::Uint32 idReq;
    msg >> idReq;

    while (!msg.endOfPacket()) {

        sf::Uint8 id;
        float shipAngle;
        float sailAngle;
        float positionX;
        float positionY;
        float speedX;
        float speedY;

        msg >> id >> shipAngle >> sailAngle >> positionX >> positionY >> speedX >> speedY;

        Ship &ship = m_world.getShips()[static_cast<unsigned int> (id)];
        ship.setAngle(shipAngle);
        ship.getSail().setAngle(sailAngle);
        ship.position() = {positionX, positionY};
        ship.velocity() = {speedX, speedY};
        std::cout << "Recv ship(" << static_cast<unsigned int> (id) << ") pos(" << positionX << "," << positionY << ") speed(" << speedX << "," << speedY << ")" << std::endl;
    }

    updatePrediction(idReq);
    return true;
}

void ClientStateGameStarted::updatePrediction(sf::Uint32 reqId) {
    std::vector<Input> predictions = m_predictions.getInputFrom(reqId);
    std::cout << "nbPrediction(" << predictions.size() << ")" << std::endl;
    Input* prevInput = &predictions[0];

    sf::Vector2f oldShipPos = m_world.getClientShip().getPosition();

    for (unsigned int i = 1; i < predictions.size(); ++i) {

        // Set state of world
        Ship& ship = m_world.getClientShip();
        ship.setTurningNegative(prevInput->getActions().test(TURN_HELM_NEGATIVE));
        ship.setTurningPositive(prevInput->getActions().test(TURN_HELM_POSITIVE));
        ship.getSail().setTurningNegative(prevInput->getActions().test(TURN_SAIL_NEGATIVE));
        ship.getSail().setTurningPositive(prevInput->getActions().test(TURN_SAIL_POSITIVE));

        // Update
        sf::Time diffTime = predictions[i].getTime() - prevInput->getTime();
        m_world.updateShip(m_world.getClientShip(), diffTime.asSeconds());

        // Go to the next predictions
        prevInput = &predictions[i];
    }

    // Set state of world
    Ship& ship = m_world.getClientShip();
    sf::Vector2f& newShipPos = ship.position();

    // Smouth correction
    sf::Vector2f diffPos = newShipPos - oldShipPos;
    if(std::abs(diffPos.x) < 1) {
        newShipPos.x =  oldShipPos.x + (diffPos.x * 0.2);
    }
    if(std::abs(diffPos.y) < 1) {
        newShipPos.y =  oldShipPos.y + (diffPos.y * 0.2);
    }

    ship.setTurningNegative(prevInput->getActions().test(TURN_HELM_NEGATIVE));
    ship.setTurningPositive(prevInput->getActions().test(TURN_HELM_POSITIVE));
    ship.getSail().setTurningNegative(prevInput->getActions().test(TURN_SAIL_NEGATIVE));
    ship.getSail().setTurningPositive(prevInput->getActions().test(TURN_SAIL_POSITIVE));

}

bool ClientStateGameStarted::readCheckpoint(MsgData& msg) {
    sf::Uint8 idCheckpoint;

    msg >> idCheckpoint;
    m_world.getCheckPointManager().getCheckPoint(idCheckpoint).activate();
    return true;
}

bool ClientStateGameStarted::readDisconnect(MsgData & msg) {
    sf::Uint8 id;
    msg >> id;
    std::cout << m_world.getShips().erase(static_cast<unsigned int> (id)) << std::endl;
    m_detailsView->updateShips();
    std::cout << "Ship of player " << static_cast<unsigned int> (id) << " remove and view update" << std::endl;
    return true;
}

bool ClientStateGameStarted::readMsgEnd(MsgData & msg) {
    m_manager.push(EStateGame::End);
    return true;
}<|endoftext|>


<commit_before>#include "rpcconsole.h"
#include "ui_rpcconsole.h"

#include "clientmodel.h"
#include "bitcoinrpc.h"
#include "guiutil.h"

#include <QTime>
#include <QTimer>
#include <QThread>
#include <QTextEdit>
#include <QKeyEvent>
#include <QUrl>
#include <QScrollBar>

#include <openssl/crypto.h>

// TODO: make it possible to filter out categories (esp debug messages when implemented)
// TODO: receive errors and debug messages through ClientModel

const int CONSOLE_SCROLLBACK = 50;
const int CONSOLE_HISTORY = 50;

const QSize ICON_SIZE(24, 24);

const struct {
    const char *url;
    const char *source;
} ICON_MAPPING[] = {
    {"cmd-request", ":/icons/tx_input"},
    {"cmd-reply", ":/icons/tx_output"},
    {"cmd-error", ":/icons/tx_output"},
    {"misc", ":/icons/tx_inout"},
    {NULL, NULL}
};

/* Object for executing console RPC commands in a separate thread.
*/
class RPCExecutor: public QObject
{
    Q_OBJECT
public slots:
    void start();
    void request(const QString &command);
signals:
    void reply(int category, const QString &command);
};

#include "rpcconsole.moc"

void RPCExecutor::start()
{
   // Nothing to do
}

/**
 * Split shell command line into a list of arguments. Aims to emulate \c bash and friends.
 *
 * - Arguments are delimited with whitespace
 * - Extra whitespace at the beginning and end and between arguments will be ignored
 * - Text can be "double" or 'single' quoted
 * - The backslash \c \ is used as escape character
 *   - Outside quotes, any character can be escaped
 *   - Within double quotes, only escape \c " and backslashes before a \c " or another backslash
 *   - Within single quotes, no escaping is possible and no special interpretation takes place
 *
 * @param[out]   args        Parsed arguments will be appended to this list
 * @param[in]    strCommand  Command line to split
 */
bool parseCommandLine(std::vector<std::string> &args, const std::string &strCommand)
{
    enum CmdParseState
    {
        STATE_EATING_SPACES,
        STATE_ARGUMENT,
        STATE_SINGLEQUOTED,
        STATE_DOUBLEQUOTED,
        STATE_ESCAPE_OUTER,
        STATE_ESCAPE_DOUBLEQUOTED
    } state = STATE_EATING_SPACES;
    std::string curarg;
    foreach(char ch, strCommand)
    {
        switch(state)
        {
        case STATE_ARGUMENT: // In or after argument
        case STATE_EATING_SPACES: // Handle runs of whitespace
            switch(ch)
            {
            case '"': state = STATE_DOUBLEQUOTED; break;
            case '\'': state = STATE_SINGLEQUOTED; break;
            case '\\': state = STATE_ESCAPE_OUTER; break;
            case ' ': case '\n': case '\t':
                if(state == STATE_ARGUMENT) // Space ends argument
                {
                    args.push_back(curarg);
                    curarg.clear();
                }
                state = STATE_EATING_SPACES;
                break;
            default: curarg += ch; state = STATE_ARGUMENT;
            }
            break;
        case STATE_SINGLEQUOTED: // Single-quoted string
            switch(ch)
            {
            case '\'': state = STATE_ARGUMENT; break;
            default: curarg += ch;
            }
            break;
        case STATE_DOUBLEQUOTED: // Double-quoted string
            switch(ch)
            {
            case '"': state = STATE_ARGUMENT; break;
            case '\\': state = STATE_ESCAPE_DOUBLEQUOTED; break;
            default: curarg += ch;
            }
            break;
        case STATE_ESCAPE_OUTER: // '\' outside quotes
            curarg += ch; state = STATE_ARGUMENT;
            break;
        case STATE_ESCAPE_DOUBLEQUOTED: // '\' in double-quoted text
            if(ch != '"' && ch != '\\') curarg += '\\'; // keep '\' for everything but the quote and '\' itself
            curarg += ch; state = STATE_DOUBLEQUOTED;
            break;
        }
    }
    switch(state) // final state
    {
    case STATE_EATING_SPACES:
        return true;
    case STATE_ARGUMENT:
        args.push_back(curarg);
        return true;
    default: // ERROR to end in one of the other states
        return false;
    }
}

void RPCExecutor::request(const QString &command)
{
    std::vector<std::string> args;
    if(!parseCommandLine(args, command.toStdString()))
    {
        emit reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \""));
        return;
    }
    if(args.empty())
        return; // Nothing to do
    try
    {
        std::string strPrint;
        // Convert argument list to JSON objects in method-dependent way,
        // and pass it along with the method name to the dispatcher.
        json_spirit::Value result = tableRPC.execute(
            args[0],
            RPCConvertValues(args[0], std::vector<std::string>(args.begin() + 1, args.end())));

        // Format result reply
        if (result.type() == json_spirit::null_type)
            strPrint = "";
        else if (result.type() == json_spirit::str_type)
            strPrint = result.get_str();
        else
            strPrint = write_string(result, true);

        emit reply(RPCConsole::CMD_REPLY, QString::fromStdString(strPrint));
    }
    catch (json_spirit::Object& objError)
    {
        try // Nice formatting for standard-format error
        {
            int code = find_value(objError, "code").get_int();
            std::string message = find_value(objError, "message").get_str();
            emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(message) + " (code " + QString::number(code) + ")");
        }
        catch(std::runtime_error &) // raised when converting to invalid type, i.e. missing code or message
        {   // Show raw JSON object
            emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(write_string(json_spirit::Value(objError), false)));
        }
    }
    catch (std::exception& e)
    {
        emit reply(RPCConsole::CMD_ERROR, QString("Error: ") + QString::fromStdString(e.what()));
    }
}

RPCConsole::RPCConsole(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::RPCConsole),
    historyPtr(0)
{
    ui->setupUi(this);

#ifndef Q_WS_MAC
    ui->openDebugLogfileButton->setIcon(QIcon(":/icons/export"));
    ui->showCLOptionsButton->setIcon(QIcon(":/icons/options"));
#endif

    // Install event filter for up and down arrow
    ui->lineEdit->installEventFilter(this);

    connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear()));

    // set OpenSSL version label
    ui->openSSLVersion->setText(SSLeay_version(SSLEAY_VERSION));

    startExecutor();

    clear();
}

RPCConsole::~RPCConsole()
{
    emit stopExecutor();
    delete ui;
}

bool RPCConsole::eventFilter(QObject* obj, QEvent *event)
{
    if(obj == ui->lineEdit)
    {
        if(event->type() == QEvent::KeyPress)
        {
            QKeyEvent *key = static_cast<QKeyEvent*>(event);
            switch(key->key())
            {
            case Qt::Key_Up: browseHistory(-1); return true;
            case Qt::Key_Down: browseHistory(1); return true;
            }
        }
    }
    return QDialog::eventFilter(obj, event);
}

void RPCConsole::setClientModel(ClientModel *model)
{
    this->clientModel = model;
    if(model)
    {
        // Subscribe to information, replies, messages, errors
        connect(model, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
        connect(model, SIGNAL(numBlocksChanged(int,int)), this, SLOT(setNumBlocks(int,int)));

        // Provide initial values
        ui->clientVersion->setText(model->formatFullVersion());
        ui->clientName->setText(model->clientName());
        ui->buildDate->setText(model->formatBuildDate());
        ui->startupTime->setText(model->formatClientStartupTime());

        setNumConnections(model->getNumConnections());
        ui->isTestNet->setChecked(model->isTestNet());

        setNumBlocks(model->getNumBlocks(), model->getNumBlocksOfPeers());
    }
}

static QString categoryClass(int category)
{
    switch(category)
    {
    case RPCConsole::CMD_REQUEST:  return "cmd-request"; break;
    case RPCConsole::CMD_REPLY:    return "cmd-reply"; break;
    case RPCConsole::CMD_ERROR:    return "cmd-error"; break;
    default:                       return "misc";
    }
}

void RPCConsole::clear()
{
    ui->messagesWidget->clear();
    ui->lineEdit->clear();
    ui->lineEdit->setFocus();

    // Add smoothly scaled icon images.
    // (when using width/height on an img, Qt uses nearest instead of linear interpolation)
    for(int i=0; ICON_MAPPING[i].url; ++i)
    {
        ui->messagesWidget->document()->addResource(
                    QTextDocument::ImageResource,
                    QUrl(ICON_MAPPING[i].url),
                    QImage(ICON_MAPPING[i].source).scaled(ICON_SIZE, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
    }

    // Set default style sheet
    ui->messagesWidget->document()->setDefaultStyleSheet(
                "table { }"
                "td.time { color: #808080; padding-top: 3px; } "
                "td.message { font-family: Monospace; font-size: 12px; } "
                "td.cmd-request { color: #006060; } "
                "td.cmd-error { color: red; } "
                "b { color: #006060; } "
                );

    message(CMD_REPLY, (tr("Welcome to the Bitcoin RPC console.") + "
" +
                        tr("Use up and down arrows to navigate history, and Ctrl-L to clear screen.") + "
" +
                        tr("Type help for an overview of available commands.")), true);
}

void RPCConsole::message(int category, const QString &message, bool html)
{
    QTime time = QTime::currentTime();
    QString timeString = time.toString();
    QString out;
    out += "

" + timeString + "	";
    out += "	";
    out += "";
    if(html)
        out += message;
    else
        out += GUIUtil::HtmlEscape(message, true);
    out += "

";
    ui->messagesWidget->append(out);
}

void RPCConsole::setNumConnections(int count)
{
    ui->numberOfConnections->setText(QString::number(count));
}

void RPCConsole::setNumBlocks(int count, int countOfPeers)
{
    ui->numberOfBlocks->setText(QString::number(count));
    ui->totalBlocks->setText(QString::number(countOfPeers));
    if(clientModel)
    {
        // If there is no current number available display N/A instead of 0, which can't ever be true
        ui->totalBlocks->setText(clientModel->getNumBlocksOfPeers() == 0 ? tr("N/A") : QString::number(clientModel->getNumBlocksOfPeers()));
        ui->lastBlockTime->setText(clientModel->getLastBlockDate().toString());
    }
}

void RPCConsole::on_lineEdit_returnPressed()
{
    QString cmd = ui->lineEdit->text();
    ui->lineEdit->clear();

    if(!cmd.isEmpty())
    {
        message(CMD_REQUEST, cmd);
        emit cmdRequest(cmd);
        // Truncate history from current position
        history.erase(history.begin() + historyPtr, history.end());
        // Append command to history
        history.append(cmd);
        // Enforce maximum history size
        while(history.size() > CONSOLE_HISTORY)
            history.removeFirst();
        // Set pointer to end of history
        historyPtr = history.size();
        // Scroll console view to end
        scrollToEnd();
    }
}

void RPCConsole::browseHistory(int offset)
{
    historyPtr += offset;
    if(historyPtr < 0)
        historyPtr = 0;
    if(historyPtr > history.size())
        historyPtr = history.size();
    QString cmd;
    if(historyPtr < history.size())
        cmd = history.at(historyPtr);
    ui->lineEdit->setText(cmd);
}

void RPCConsole::startExecutor()
{
    QThread* thread = new QThread;
    RPCExecutor *executor = new RPCExecutor();
    executor->moveToThread(thread);

    // Notify executor when thread started (in executor thread)
    connect(thread, SIGNAL(started()), executor, SLOT(start()));
    // Replies from executor object must go to this object
    connect(executor, SIGNAL(reply(int,QString)), this, SLOT(message(int,QString)));
    // Requests from this object must go to executor
    connect(this, SIGNAL(cmdRequest(QString)), executor, SLOT(request(QString)));
    // On stopExecutor signal
    // - queue executor for deletion (in execution thread)
    // - quit the Qt event loop in the execution thread
    connect(this, SIGNAL(stopExecutor()), executor, SLOT(deleteLater()));
    connect(this, SIGNAL(stopExecutor()), thread, SLOT(quit()));
    // Queue the thread for deletion (in this thread) when it is finished
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

    // Default implementation of QThread::run() simply spins up an event loop in the thread,
    // which is what we want.
    thread->start();
}

void RPCConsole::on_tabWidget_currentChanged(int index)
{
    if(ui->tabWidget->widget(index) == ui->tab_console)
    {
        ui->lineEdit->setFocus();
    }
}

void RPCConsole::on_openDebugLogfileButton_clicked()
{
    GUIUtil::openDebugLogfile();
}

void RPCConsole::scrollToEnd()
{
    QScrollBar *scrollbar = ui->messagesWidget->verticalScrollBar();
    scrollbar->setValue(scrollbar->maximum());
}

void RPCConsole::on_showCLOptionsButton_clicked()
{
    GUIUtil::HelpMessageBox help;
    help.exec();
}
<commit_msg>clear history when using clear button in RPC console<commit_after>#include "rpcconsole.h"
#include "ui_rpcconsole.h"

#include "clientmodel.h"
#include "bitcoinrpc.h"
#include "guiutil.h"

#include <QTime>
#include <QTimer>
#include <QThread>
#include <QTextEdit>
#include <QKeyEvent>
#include <QUrl>
#include <QScrollBar>

#include <openssl/crypto.h>

// TODO: add a scrollback limit, as there is currently none
// TODO: make it possible to filter out categories (esp debug messages when implemented)
// TODO: receive errors and debug messages through ClientModel

const int CONSOLE_HISTORY = 50;
const QSize ICON_SIZE(24, 24);

const struct {
    const char *url;
    const char *source;
} ICON_MAPPING[] = {
    {"cmd-request", ":/icons/tx_input"},
    {"cmd-reply", ":/icons/tx_output"},
    {"cmd-error", ":/icons/tx_output"},
    {"misc", ":/icons/tx_inout"},
    {NULL, NULL}
};

/* Object for executing console RPC commands in a separate thread.
*/
class RPCExecutor: public QObject
{
    Q_OBJECT
public slots:
    void start();
    void request(const QString &command);
signals:
    void reply(int category, const QString &command);
};

#include "rpcconsole.moc"

void RPCExecutor::start()
{
   // Nothing to do
}

/**
 * Split shell command line into a list of arguments. Aims to emulate \c bash and friends.
 *
 * - Arguments are delimited with whitespace
 * - Extra whitespace at the beginning and end and between arguments will be ignored
 * - Text can be "double" or 'single' quoted
 * - The backslash \c \ is used as escape character
 *   - Outside quotes, any character can be escaped
 *   - Within double quotes, only escape \c " and backslashes before a \c " or another backslash
 *   - Within single quotes, no escaping is possible and no special interpretation takes place
 *
 * @param[out]   args        Parsed arguments will be appended to this list
 * @param[in]    strCommand  Command line to split
 */
bool parseCommandLine(std::vector<std::string> &args, const std::string &strCommand)
{
    enum CmdParseState
    {
        STATE_EATING_SPACES,
        STATE_ARGUMENT,
        STATE_SINGLEQUOTED,
        STATE_DOUBLEQUOTED,
        STATE_ESCAPE_OUTER,
        STATE_ESCAPE_DOUBLEQUOTED
    } state = STATE_EATING_SPACES;
    std::string curarg;
    foreach(char ch, strCommand)
    {
        switch(state)
        {
        case STATE_ARGUMENT: // In or after argument
        case STATE_EATING_SPACES: // Handle runs of whitespace
            switch(ch)
            {
            case '"': state = STATE_DOUBLEQUOTED; break;
            case '\'': state = STATE_SINGLEQUOTED; break;
            case '\\': state = STATE_ESCAPE_OUTER; break;
            case ' ': case '\n': case '\t':
                if(state == STATE_ARGUMENT) // Space ends argument
                {
                    args.push_back(curarg);
                    curarg.clear();
                }
                state = STATE_EATING_SPACES;
                break;
            default: curarg += ch; state = STATE_ARGUMENT;
            }
            break;
        case STATE_SINGLEQUOTED: // Single-quoted string
            switch(ch)
            {
            case '\'': state = STATE_ARGUMENT; break;
            default: curarg += ch;
            }
            break;
        case STATE_DOUBLEQUOTED: // Double-quoted string
            switch(ch)
            {
            case '"': state = STATE_ARGUMENT; break;
            case '\\': state = STATE_ESCAPE_DOUBLEQUOTED; break;
            default: curarg += ch;
            }
            break;
        case STATE_ESCAPE_OUTER: // '\' outside quotes
            curarg += ch; state = STATE_ARGUMENT;
            break;
        case STATE_ESCAPE_DOUBLEQUOTED: // '\' in double-quoted text
            if(ch != '"' && ch != '\\') curarg += '\\'; // keep '\' for everything but the quote and '\' itself
            curarg += ch; state = STATE_DOUBLEQUOTED;
            break;
        }
    }
    switch(state) // final state
    {
    case STATE_EATING_SPACES:
        return true;
    case STATE_ARGUMENT:
        args.push_back(curarg);
        return true;
    default: // ERROR to end in one of the other states
        return false;
    }
}

void RPCExecutor::request(const QString &command)
{
    std::vector<std::string> args;
    if(!parseCommandLine(args, command.toStdString()))
    {
        emit reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \""));
        return;
    }
    if(args.empty())
        return; // Nothing to do
    try
    {
        std::string strPrint;
        // Convert argument list to JSON objects in method-dependent way,
        // and pass it along with the method name to the dispatcher.
        json_spirit::Value result = tableRPC.execute(
            args[0],
            RPCConvertValues(args[0], std::vector<std::string>(args.begin() + 1, args.end())));

        // Format result reply
        if (result.type() == json_spirit::null_type)
            strPrint = "";
        else if (result.type() == json_spirit::str_type)
            strPrint = result.get_str();
        else
            strPrint = write_string(result, true);

        emit reply(RPCConsole::CMD_REPLY, QString::fromStdString(strPrint));
    }
    catch (json_spirit::Object& objError)
    {
        try // Nice formatting for standard-format error
        {
            int code = find_value(objError, "code").get_int();
            std::string message = find_value(objError, "message").get_str();
            emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(message) + " (code " + QString::number(code) + ")");
        }
        catch(std::runtime_error &) // raised when converting to invalid type, i.e. missing code or message
        {   // Show raw JSON object
            emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(write_string(json_spirit::Value(objError), false)));
        }
    }
    catch (std::exception& e)
    {
        emit reply(RPCConsole::CMD_ERROR, QString("Error: ") + QString::fromStdString(e.what()));
    }
}

RPCConsole::RPCConsole(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::RPCConsole),
    historyPtr(0)
{
    ui->setupUi(this);

#ifndef Q_WS_MAC
    ui->openDebugLogfileButton->setIcon(QIcon(":/icons/export"));
    ui->showCLOptionsButton->setIcon(QIcon(":/icons/options"));
#endif

    // Install event filter for up and down arrow
    ui->lineEdit->installEventFilter(this);

    connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear()));

    // set OpenSSL version label
    ui->openSSLVersion->setText(SSLeay_version(SSLEAY_VERSION));

    startExecutor();

    clear();
}

RPCConsole::~RPCConsole()
{
    emit stopExecutor();
    delete ui;
}

bool RPCConsole::eventFilter(QObject* obj, QEvent *event)
{
    if(obj == ui->lineEdit)
    {
        if(event->type() == QEvent::KeyPress)
        {
            QKeyEvent *key = static_cast<QKeyEvent*>(event);
            switch(key->key())
            {
            case Qt::Key_Up: browseHistory(-1); return true;
            case Qt::Key_Down: browseHistory(1); return true;
            }
        }
    }
    return QDialog::eventFilter(obj, event);
}

void RPCConsole::setClientModel(ClientModel *model)
{
    this->clientModel = model;
    if(model)
    {
        // Subscribe to information, replies, messages, errors
        connect(model, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
        connect(model, SIGNAL(numBlocksChanged(int,int)), this, SLOT(setNumBlocks(int,int)));

        // Provide initial values
        ui->clientVersion->setText(model->formatFullVersion());
        ui->clientName->setText(model->clientName());
        ui->buildDate->setText(model->formatBuildDate());
        ui->startupTime->setText(model->formatClientStartupTime());

        setNumConnections(model->getNumConnections());
        ui->isTestNet->setChecked(model->isTestNet());

        setNumBlocks(model->getNumBlocks(), model->getNumBlocksOfPeers());
    }
}

static QString categoryClass(int category)
{
    switch(category)
    {
    case RPCConsole::CMD_REQUEST:  return "cmd-request"; break;
    case RPCConsole::CMD_REPLY:    return "cmd-reply"; break;
    case RPCConsole::CMD_ERROR:    return "cmd-error"; break;
    default:                       return "misc";
    }
}

void RPCConsole::clear()
{
    ui->messagesWidget->clear();
    history.clear();
    historyPtr = 0;
    ui->lineEdit->clear();
    ui->lineEdit->setFocus();

    // Add smoothly scaled icon images.
    // (when using width/height on an img, Qt uses nearest instead of linear interpolation)
    for(int i=0; ICON_MAPPING[i].url; ++i)
    {
        ui->messagesWidget->document()->addResource(
                    QTextDocument::ImageResource,
                    QUrl(ICON_MAPPING[i].url),
                    QImage(ICON_MAPPING[i].source).scaled(ICON_SIZE, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
    }

    // Set default style sheet
    ui->messagesWidget->document()->setDefaultStyleSheet(
                "table { }"
                "td.time { color: #808080; padding-top: 3px; } "
                "td.message { font-family: Monospace; font-size: 12px; } "
                "td.cmd-request { color: #006060; } "
                "td.cmd-error { color: red; } "
                "b { color: #006060; } "
                );

    message(CMD_REPLY, (tr("Welcome to the Bitcoin RPC console.") + "
" +
                        tr("Use up and down arrows to navigate history, and Ctrl-L to clear screen.") + "
" +
                        tr("Type help for an overview of available commands.")), true);
}

void RPCConsole::message(int category, const QString &message, bool html)
{
    QTime time = QTime::currentTime();
    QString timeString = time.toString();
    QString out;
    out += "

" + timeString + "	";
    out += "	";
    out += "";
    if(html)
        out += message;
    else
        out += GUIUtil::HtmlEscape(message, true);
    out += "

";
    ui->messagesWidget->append(out);
}

void RPCConsole::setNumConnections(int count)
{
    ui->numberOfConnections->setText(QString::number(count));
}

void RPCConsole::setNumBlocks(int count, int countOfPeers)
{
    ui->numberOfBlocks->setText(QString::number(count));
    ui->totalBlocks->setText(QString::number(countOfPeers));
    if(clientModel)
    {
        // If there is no current number available display N/A instead of 0, which can't ever be true
        ui->totalBlocks->setText(clientModel->getNumBlocksOfPeers() == 0 ? tr("N/A") : QString::number(clientModel->getNumBlocksOfPeers()));
        ui->lastBlockTime->setText(clientModel->getLastBlockDate().toString());
    }
}

void RPCConsole::on_lineEdit_returnPressed()
{
    QString cmd = ui->lineEdit->text();
    ui->lineEdit->clear();

    if(!cmd.isEmpty())
    {
        message(CMD_REQUEST, cmd);
        emit cmdRequest(cmd);
        // Truncate history from current position
        history.erase(history.begin() + historyPtr, history.end());
        // Append command to history
        history.append(cmd);
        // Enforce maximum history size
        while(history.size() > CONSOLE_HISTORY)
            history.removeFirst();
        // Set pointer to end of history
        historyPtr = history.size();
        // Scroll console view to end
        scrollToEnd();
    }
}

void RPCConsole::browseHistory(int offset)
{
    historyPtr += offset;
    if(historyPtr < 0)
        historyPtr = 0;
    if(historyPtr > history.size())
        historyPtr = history.size();
    QString cmd;
    if(historyPtr < history.size())
        cmd = history.at(historyPtr);
    ui->lineEdit->setText(cmd);
}

void RPCConsole::startExecutor()
{
    QThread* thread = new QThread;
    RPCExecutor *executor = new RPCExecutor();
    executor->moveToThread(thread);

    // Notify executor when thread started (in executor thread)
    connect(thread, SIGNAL(started()), executor, SLOT(start()));
    // Replies from executor object must go to this object
    connect(executor, SIGNAL(reply(int,QString)), this, SLOT(message(int,QString)));
    // Requests from this object must go to executor
    connect(this, SIGNAL(cmdRequest(QString)), executor, SLOT(request(QString)));
    // On stopExecutor signal
    // - queue executor for deletion (in execution thread)
    // - quit the Qt event loop in the execution thread
    connect(this, SIGNAL(stopExecutor()), executor, SLOT(deleteLater()));
    connect(this, SIGNAL(stopExecutor()), thread, SLOT(quit()));
    // Queue the thread for deletion (in this thread) when it is finished
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

    // Default implementation of QThread::run() simply spins up an event loop in the thread,
    // which is what we want.
    thread->start();
}

void RPCConsole::on_tabWidget_currentChanged(int index)
{
    if(ui->tabWidget->widget(index) == ui->tab_console)
    {
        ui->lineEdit->setFocus();
    }
}

void RPCConsole::on_openDebugLogfileButton_clicked()
{
    GUIUtil::openDebugLogfile();
}

void RPCConsole::scrollToEnd()
{
    QScrollBar *scrollbar = ui->messagesWidget->verticalScrollBar();
    scrollbar->setValue(scrollbar->maximum());
}

void RPCConsole::on_showCLOptionsButton_clicked()
{
    GUIUtil::HelpMessageBox help;
    help.exec();
}
<|endoftext|>


<commit_before>#include "recorder_node.h"

#include <cinder/audio/Context.h>

namespace cieq {
namespace audio {

RecorderNode::RecorderNode(size_t numFrames, const Format &format /*= Format()*/)
	: inherited(numFrames, format)
	, mWindowSize(format.getWindowSize())
	, mHopSize(format.getHopSize())
	, mLastQueried(0)
{
	mMaxPopsPossible = (getNumFrames() - getWindowSize()) / getHopSize();
	if ((getNumFrames() - getWindowSize()) % getHopSize() != 0)
		mMaxPopsPossible += 1;
}

RecorderNode::RecorderNode(const Format &format /*= Format()*/)
	: RecorderNode(0.0f, format)
{}

RecorderNode::RecorderNode(float numSeconds, const Format &format /*= Format()*/)
	: RecorderNode(static_cast<size_t>(ci::audio::Context::master()->getSampleRate() * numSeconds), format)
{}

ci::audio::BufferDynamic& RecorderNode::getBufferRaw()
{
	return mRecorderBuffer;
}

void RecorderNode::getBufferChunk(size_t start, size_t len, ci::audio::Buffer& other)
{
	other.copyOffset(getBufferRaw(), len, 0, start);
}

void RecorderNode::getBufferChunk(size_t start, ci::audio::Buffer& other)
{
	getBufferChunk(start, mWindowSize, other);
}

bool RecorderNode::popBufferWindow(ci::audio::Buffer& other)
{
	if (!isRecording()) return false;

	if (mLastQueried + mWindowSize <= getWritePosition())
	{
		getBufferChunk(mLastQueried, other);
		mLastQueried += mHopSize;
		return true;
	}
	// This is the critical situation that can happen at the end of samples
	// where there's not enough number of samples for the last buffer.
	else if (getNumFrames() - mLastQueried < mWindowSize)
	{
		getBufferChunk(mLastQueried, getNumFrames() - mLastQueried, other);
		mLastQueried = getNumFrames();
		return true;
	}
	else
	{
		return false;
	}
}

bool RecorderNode::popBufferWindow(size_t& query_pos)
{
	if (!isRecording()) return false;

	if (mLastQueried + mWindowSize <= getWritePosition())
	{
		query_pos = mLastQueried;
		mLastQueried += mHopSize;
		return true;
	}
	// This is the critical situation that can happen at the end of samples
	// where there's not enough number of samples for the last buffer.
	else if (getNumFrames() - mLastQueried < mWindowSize)
	{
		query_pos = mLastQueried;
		mLastQueried = getNumFrames();
		return true;
	}
	else
	{
		return false;
	}
}

bool RecorderNode::popBufferWindow(ci::audio::Buffer& other, size_t query_pos)
{
	if (query_pos + mWindowSize <= getWritePosition())
	{
		getBufferChunk(query_pos, other);
		query_pos += mHopSize;
		return true;
	}
	// This is the critical situation that can happen at the end of samples
	// where there's not enough number of samples for the last buffer.
	else if (getNumFrames() - query_pos < mWindowSize)
	{
		getBufferChunk(query_pos, getNumFrames() - query_pos, other);
		query_pos = getNumFrames();
		return true;
	}
	else
	{
		return false;
	}
}

size_t RecorderNode::getWindowSize() const
{
	return mWindowSize;
}

size_t RecorderNode::getHopSize() const
{
	return mHopSize;
}

bool RecorderNode::isRecording() const
{
	return getWritePosition() != getNumFrames();
}

size_t RecorderNode::getMaxPossiblePops() const
{
	return mMaxPopsPossible;
}

size_t RecorderNode::getQueryIndexByQueryPos(size_t pos)
{
	return pos / mHopSize;
}

void RecorderNode::reset()
{
	mLastQueried = 0;
}

}} //!cieq::node<commit_msg>Fixed a math issue for calculating max number of hops possible<commit_after>#include "recorder_node.h"

#include <cinder/audio/Context.h>

namespace cieq {
namespace audio {

RecorderNode::RecorderNode(size_t numFrames, const Format &format /*= Format()*/)
	: inherited(numFrames, format)
	, mWindowSize(format.getWindowSize())
	, mHopSize(format.getHopSize())
	, mLastQueried(0)
{
	mMaxPopsPossible = getNumFrames() / getHopSize();
	if (getNumFrames() % getHopSize() == 0)
		mMaxPopsPossible -= 1; //special case where last chunk will be equal to one hop
}

RecorderNode::RecorderNode(const Format &format /*= Format()*/)
	: RecorderNode(0.0f, format)
{}

RecorderNode::RecorderNode(float numSeconds, const Format &format /*= Format()*/)
	: RecorderNode(static_cast<size_t>(ci::audio::Context::master()->getSampleRate() * numSeconds), format)
{}

ci::audio::BufferDynamic& RecorderNode::getBufferRaw()
{
	return mRecorderBuffer;
}

void RecorderNode::getBufferChunk(size_t start, size_t len, ci::audio::Buffer& other)
{
	other.copyOffset(getBufferRaw(), len, 0, start);
}

void RecorderNode::getBufferChunk(size_t start, ci::audio::Buffer& other)
{
	getBufferChunk(start, mWindowSize, other);
}

bool RecorderNode::popBufferWindow(ci::audio::Buffer& other)
{
	if (!isRecording()) return false;

	if (mLastQueried + mWindowSize <= getWritePosition())
	{
		getBufferChunk(mLastQueried, other);
		mLastQueried += mHopSize;
		return true;
	}
	// This is the critical situation that can happen at the end of samples
	// where there's not enough number of samples for the last buffer.
	else if (getNumFrames() - mLastQueried < mWindowSize)
	{
		getBufferChunk(mLastQueried, getNumFrames() - mLastQueried, other);
		mLastQueried = getNumFrames();
		return true;
	}
	else
	{
		return false;
	}
}

bool RecorderNode::popBufferWindow(size_t& query_pos)
{
	if (!isRecording()) return false;

	if (mLastQueried + mWindowSize <= getWritePosition())
	{
		query_pos = mLastQueried;
		mLastQueried += mHopSize;
		return true;
	}
	// This is the critical situation that can happen at the end of samples
	// where there's not enough number of samples for the last buffer.
	else if (getNumFrames() - mLastQueried < mWindowSize)
	{
		query_pos = mLastQueried;
		mLastQueried = getNumFrames();
		return true;
	}
	else
	{
		return false;
	}
}

bool RecorderNode::popBufferWindow(ci::audio::Buffer& other, size_t query_pos)
{
	if (query_pos + mWindowSize <= getWritePosition())
	{
		getBufferChunk(query_pos, other);
		query_pos += mHopSize;
		return true;
	}
	// This is the critical situation that can happen at the end of samples
	// where there's not enough number of samples for the last buffer.
	else if (getNumFrames() - query_pos < mWindowSize)
	{
		getBufferChunk(query_pos, getNumFrames() - query_pos, other);
		query_pos = getNumFrames();
		return true;
	}
	else
	{
		return false;
	}
}

size_t RecorderNode::getWindowSize() const
{
	return mWindowSize;
}

size_t RecorderNode::getHopSize() const
{
	return mHopSize;
}

bool RecorderNode::isRecording() const
{
	return getWritePosition() != getNumFrames();
}

size_t RecorderNode::getMaxPossiblePops() const
{
	return mMaxPopsPossible;
}

size_t RecorderNode::getQueryIndexByQueryPos(size_t pos)
{
	return pos / mHopSize;
}

void RecorderNode::reset()
{
	mLastQueried = 0;
}

}} //!cieq::node<|endoftext|>


<commit_before>/*
 * Functions deal with the regex banning.
 *
 * Copyright (c) eQualit.ie 2013 under GNU AGPL v3.0 or later
 *
 *  Vmon: June 2013, Initial version
 */
#include <vector>
#include <sys/time.h>

#include "regex_manager.h"

using namespace std;

/**
  reads all the regular expressions from the database.
  and compile them
 */
void RegexManager::load_config()
{
  try
  {
    TSDebug(BANJAX_PLUGIN_NAME, "Setting regex re2 options");
    RE2::Options opt;
    opt.set_log_errors(false);
    opt.set_perl_classes(true);
    opt.set_posix_syntax(true);

    TSDebug(BANJAX_PLUGIN_NAME, "Loading regex manager conf");

    for (const auto& node : cfg) {
      string cur_rule = node["rule"].as<std::string>();

      TSDebug(BANJAX_PLUGIN_NAME, "initiating rule %s", cur_rule.c_str());

      unsigned int observation_interval = node["interval"].as<unsigned int>();
      unsigned int threshold = node["hits_per_interval"].as<unsigned int>();

      rated_banning_regexes.emplace_back(
          new RatedRegex(rated_banning_regexes.size(),
                         cur_rule,
                         new RE2(node["regex"].as<std::string>(), opt),
                         observation_interval * 1000,
                         threshold /(double)(observation_interval* 1000)));
    }

    total_no_of_rules = rated_banning_regexes.size();
  }
  catch(YAML::RepresentationException& e)
  {
    TSDebug(BANJAX_PLUGIN_NAME, "Error loading regex manager conf [%s].", e.what());
    throw;
  }

  TSDebug(BANJAX_PLUGIN_NAME, "Done loading regex manager conf");
}

/**
  applies all regex to an ATS record

  @param ats_record: the full request record including time url agent etc
  @return: 1 match 0 not match < 0 error.
*/
pair<RegexManager::RegexResult,RegexManager::RatedRegex*>
RegexManager::parse_request(string ip, string ats_record) const
{
  boost::optional<IpDb::IpState> ip_state;

  for(const auto& rule : rated_banning_regexes) {
    if (RE2::FullMatch(ats_record, *(rule->re2_regex))) {
        TSDebug(BANJAX_PLUGIN_NAME, "requests matched %s", (rule->re2_regex->pattern()).c_str());
        //if it is a simple regex i.e. with rate 0 we bans immidiately without
        //wasting time and mem
        if (rule->rate == 0) {
          TSDebug(BANJAX_PLUGIN_NAME, "simple regex, ban immediately");
          return make_pair(REGEX_MATCHED, rule.get());
        }
        //select appropriate rate, dependent on whether GET or POST request

        /* we need to check the rate condition here */
        //getting current time in msec
        timeval cur_time; gettimeofday(&cur_time, NULL);
        long cur_time_msec = cur_time.tv_sec * 1000 + cur_time.tv_usec / 1000.0;

        /* first we check if we already have retreived the state for this ip */
        if (!ip_state || ip_state->size() == 0) {
          ip_state =  regex_manager_ip_db->get_ip_state(ip);
          if (!ip_state) //we failed to read the database we make no judgement
            continue;
        }

        //if we succeeded in retreiving but the size is zero then it meaens we don't have a record of this ip at all
        if (ip_state->size() == 0) {
          ip_state->resize(total_no_of_rules);
        }

        //now we check the begining of the hit for this regex (if the vector is just created everything is 0, in case
        //this is the first regex this ip hits)
        RegexState state = (*ip_state)[rule->id];

        //if it is 0, then we don't have a record for
        //the current regex
        if (state.begin_msec == 0) {
          state.begin_msec = cur_time_msec;
        }

        //now we have a record, update the rate and ban if necessary.
        //we move the interval by the differences of the "begin_in_ms - cur_time_msec - interval*1000"
        //if it is less than zero we don't do anything just augument the rate
        long time_window_movement = cur_time_msec - state.begin_msec - rule->interval;
        if (time_window_movement > 0) { //we need to move
           state.begin_msec += time_window_movement;
           state.rate = state.rate - (state.rate * time_window_movement - 1)/(double) rule->interval;
           state.rate = state.rate < 0 ? 1/(double) rule->interval : state.rate; //if time_window_movement > time_window_movementrule->interval, then we just wipe history and start as a new interval
         }
         else {
           //we are still in the same interval so just increase the hit by 1
           state.rate += 1/(double) rule->interval;
         }

        TSDebug(BANJAX_PLUGIN_NAME, "with rate %f /msec", state.rate);

        (*ip_state)[rule->id] = state;

        if (state.rate >= rule->rate) {
          TSDebug(BANJAX_PLUGIN_NAME, "exceeding excessive rate %f /msec", rule->rate);
          //clear the record to avoid multiple reporting to swabber
          //we are not clearing the state cause it is not for sure that
          //swabber ban the ip due to possible failure of acquiring lock
          // ip_state.detail.begin_msec = 0;
          // ip_state.detail.rate = 0;
          // regex_manager_ip_db->set_ip_state(ip, ip_state.state_allocator);

          //before calling swabber we need to delete the memory as swabber will
          //delete the ip database entery and the memory will be lost.
          //However, if swabber fails to acquire a lock this means
          //the ip can escape the banning, this however is a miner
          //concern compared to the fact that we might ran out of
          //memory.

          regex_manager_ip_db->set_ip_state(ip, *ip_state);
          return make_pair(REGEX_MATCHED, rule.get());
        }
    }
  }

  //if we managed to get/make a valid state we are going to store it
  if (ip_state && ip_state->size() > 0)
    regex_manager_ip_db->set_ip_state(ip, *ip_state);

  //no match
  return make_pair(REGEX_MISSED, (RatedRegex*)NULL);
}

FilterResponse RegexManager::on_http_request(const TransactionParts& transaction_parts)
{
  const string sep(" ");
  TransactionParts ats_record_parts = (TransactionParts) transaction_parts;

  string ats_record =  ats_record_parts[TransactionMuncher::METHOD] + sep;
  ats_record+= ats_record_parts[TransactionMuncher::URL] + sep;
  ats_record+= ats_record_parts[TransactionMuncher::HOST] + sep;
  ats_record+= ats_record_parts[TransactionMuncher::UA];

  TSDebug(BANJAX_PLUGIN_NAME, "Examining '%s' for banned matches", ats_record.c_str());
  pair<RegexResult,RatedRegex*> result = parse_request(
						ats_record_parts[TransactionMuncher::IP],
						ats_record
						);

  if (result.first == REGEX_MATCHED) {
    TSDebug(BANJAX_PLUGIN_NAME, "asking swabber to ban client ip: %s", ats_record_parts[TransactionMuncher::IP].c_str());

    //here instead we are calling nosmos's banning client
    string ats_rec_comma_sep =
      ats_record_parts[TransactionMuncher::METHOD] + ", " +
      encapsulate_in_quotes(ats_record_parts[TransactionMuncher::URL]) + ", " +
      ats_record_parts[TransactionMuncher::HOST] + ", " +
      encapsulate_in_quotes(ats_record_parts[TransactionMuncher::UA]);

    string banning_reason = "matched regex rule " + result.second->rule_name + ", " + ats_rec_comma_sep;

    swabber->ban(ats_record_parts[TransactionMuncher::IP], banning_reason);
    return FilterResponse([&](const TransactionParts& a, const FilterResponse& b) { return this->generate_response(a, b); });

  } else if (result.first != REGEX_MISSED) {
    TSError("Regex failed with error: %d\n", result.first);
  }

  return FilterResponse(FilterResponse::GO_AHEAD_NO_COMMENT);

}

std::string RegexManager::generate_response(const TransactionParts& transaction_parts, const FilterResponse& response_info)
{
  (void)transaction_parts; (void)response_info;
  return forbidden_message;
}
<commit_msg>regex_manager.cpp: consistent padding<commit_after>/*
 * Functions deal with the regex banning.
 *
 * Copyright (c) eQualit.ie 2013 under GNU AGPL v3.0 or later
 *
 *  Vmon: June 2013, Initial version
 */
#include <vector>
#include <sys/time.h>

#include "regex_manager.h"

using namespace std;

/**
  reads all the regular expressions from the database.
  and compile them
 */
void RegexManager::load_config()
{
  try
  {
    TSDebug(BANJAX_PLUGIN_NAME, "Setting regex re2 options");
    RE2::Options opt;
    opt.set_log_errors(false);
    opt.set_perl_classes(true);
    opt.set_posix_syntax(true);

    TSDebug(BANJAX_PLUGIN_NAME, "Loading regex manager conf");

    for (const auto& node : cfg) {
      string cur_rule = node["rule"].as<std::string>();

      TSDebug(BANJAX_PLUGIN_NAME, "initiating rule %s", cur_rule.c_str());

      unsigned int observation_interval = node["interval"].as<unsigned int>();
      unsigned int threshold = node["hits_per_interval"].as<unsigned int>();

      rated_banning_regexes.emplace_back(
          new RatedRegex(rated_banning_regexes.size(),
                         cur_rule,
                         new RE2(node["regex"].as<std::string>(), opt),
                         observation_interval * 1000,
                         threshold /(double)(observation_interval* 1000)));
    }

    total_no_of_rules = rated_banning_regexes.size();
  }
  catch(YAML::RepresentationException& e)
  {
    TSDebug(BANJAX_PLUGIN_NAME, "Error loading regex manager conf [%s].", e.what());
    throw;
  }

  TSDebug(BANJAX_PLUGIN_NAME, "Done loading regex manager conf");
}

/**
  applies all regex to an ATS record

  @param ats_record: the full request record including time url agent etc
  @return: 1 match 0 not match < 0 error.
*/
pair<RegexManager::RegexResult,RegexManager::RatedRegex*>
RegexManager::parse_request(string ip, string ats_record) const
{
  boost::optional<IpDb::IpState> ip_state;

  for(const auto& rule : rated_banning_regexes) {
    if (RE2::FullMatch(ats_record, *(rule->re2_regex))) {
      TSDebug(BANJAX_PLUGIN_NAME, "requests matched %s", (rule->re2_regex->pattern()).c_str());
      //if it is a simple regex i.e. with rate 0 we bans immidiately without
      //wasting time and mem
      if (rule->rate == 0) {
        TSDebug(BANJAX_PLUGIN_NAME, "simple regex, ban immediately");
        return make_pair(REGEX_MATCHED, rule.get());
      }
      //select appropriate rate, dependent on whether GET or POST request

      /* we need to check the rate condition here */
      //getting current time in msec
      timeval cur_time; gettimeofday(&cur_time, NULL);
      long cur_time_msec = cur_time.tv_sec * 1000 + cur_time.tv_usec / 1000.0;

      /* first we check if we already have retreived the state for this ip */
      if (!ip_state || ip_state->size() == 0) {
        ip_state =  regex_manager_ip_db->get_ip_state(ip);
        if (!ip_state) //we failed to read the database we make no judgement
          continue;
      }

      //if we succeeded in retreiving but the size is zero then it meaens we don't have a record of this ip at all
      if (ip_state->size() == 0) {
        ip_state->resize(total_no_of_rules);
      }

      //now we check the begining of the hit for this regex (if the vector is just created everything is 0, in case
      //this is the first regex this ip hits)
      RegexState state = (*ip_state)[rule->id];

      //if it is 0, then we don't have a record for
      //the current regex
      if (state.begin_msec == 0) {
        state.begin_msec = cur_time_msec;
      }

      //now we have a record, update the rate and ban if necessary.
      //we move the interval by the differences of the "begin_in_ms - cur_time_msec - interval*1000"
      //if it is less than zero we don't do anything just augument the rate
      long time_window_movement = cur_time_msec - state.begin_msec - rule->interval;
      if (time_window_movement > 0) { //we need to move
         state.begin_msec += time_window_movement;
         state.rate = state.rate - (state.rate * time_window_movement - 1)/(double) rule->interval;
         state.rate = state.rate < 0 ? 1/(double) rule->interval : state.rate; //if time_window_movement > time_window_movementrule->interval, then we just wipe history and start as a new interval
       }
       else {
         //we are still in the same interval so just increase the hit by 1
         state.rate += 1/(double) rule->interval;
       }

      TSDebug(BANJAX_PLUGIN_NAME, "with rate %f /msec", state.rate);

      (*ip_state)[rule->id] = state;

      if (state.rate >= rule->rate) {
        TSDebug(BANJAX_PLUGIN_NAME, "exceeding excessive rate %f /msec", rule->rate);
        //clear the record to avoid multiple reporting to swabber
        //we are not clearing the state cause it is not for sure that
        //swabber ban the ip due to possible failure of acquiring lock
        // ip_state.detail.begin_msec = 0;
        // ip_state.detail.rate = 0;
        // regex_manager_ip_db->set_ip_state(ip, ip_state.state_allocator);

        //before calling swabber we need to delete the memory as swabber will
        //delete the ip database entery and the memory will be lost.
        //However, if swabber fails to acquire a lock this means
        //the ip can escape the banning, this however is a miner
        //concern compared to the fact that we might ran out of
        //memory.

        regex_manager_ip_db->set_ip_state(ip, *ip_state);
        return make_pair(REGEX_MATCHED, rule.get());
      }
    }
  }

  //if we managed to get/make a valid state we are going to store it
  if (ip_state && ip_state->size() > 0)
    regex_manager_ip_db->set_ip_state(ip, *ip_state);

  //no match
  return make_pair(REGEX_MISSED, (RatedRegex*)NULL);
}

FilterResponse RegexManager::on_http_request(const TransactionParts& transaction_parts)
{
  const string sep(" ");
  TransactionParts ats_record_parts = (TransactionParts) transaction_parts;

  string ats_record =  ats_record_parts[TransactionMuncher::METHOD] + sep;
  ats_record+= ats_record_parts[TransactionMuncher::URL] + sep;
  ats_record+= ats_record_parts[TransactionMuncher::HOST] + sep;
  ats_record+= ats_record_parts[TransactionMuncher::UA];

  TSDebug(BANJAX_PLUGIN_NAME, "Examining '%s' for banned matches", ats_record.c_str());
  pair<RegexResult,RatedRegex*> result = parse_request(
						ats_record_parts[TransactionMuncher::IP],
						ats_record
						);

  if (result.first == REGEX_MATCHED) {
    TSDebug(BANJAX_PLUGIN_NAME, "asking swabber to ban client ip: %s", ats_record_parts[TransactionMuncher::IP].c_str());

    //here instead we are calling nosmos's banning client
    string ats_rec_comma_sep =
      ats_record_parts[TransactionMuncher::METHOD] + ", " +
      encapsulate_in_quotes(ats_record_parts[TransactionMuncher::URL]) + ", " +
      ats_record_parts[TransactionMuncher::HOST] + ", " +
      encapsulate_in_quotes(ats_record_parts[TransactionMuncher::UA]);

    string banning_reason = "matched regex rule " + result.second->rule_name + ", " + ats_rec_comma_sep;

    swabber->ban(ats_record_parts[TransactionMuncher::IP], banning_reason);
    return FilterResponse([&](const TransactionParts& a, const FilterResponse& b) { return this->generate_response(a, b); });

  } else if (result.first != REGEX_MISSED) {
    TSError("Regex failed with error: %d\n", result.first);
  }

  return FilterResponse(FilterResponse::GO_AHEAD_NO_COMMENT);

}

std::string RegexManager::generate_response(const TransactionParts& transaction_parts, const FilterResponse& response_info)
{
  (void)transaction_parts; (void)response_info;
  return forbidden_message;
}
<|endoftext|>


<commit_before>#include "nova_renderer/rhi/rhi_types.hpp"

namespace nova::renderer::rhi {
    bool ResourceBindingDescription::operator==(const ResourceBindingDescription& other) {
        return set == other.set && binding == other.binding && count == other.count && type == other.type;
    }

    bool ResourceBindingDescription::operator!=(const ResourceBindingDescription& other) { return !(*this == other); }

    ResourceBarrier::ResourceBarrier() {}

    DescriptorResourceInfo::DescriptorResourceInfo() {}

    uint32_t PipelineInterface::get_num_descriptors_of_type(const DescriptorType type) const {
        uint32_t num_descriptors = 0;
        for(const auto& [name, description] : bindings) {
            if(description.type == type) {
                num_descriptors++;
            }
        }

        return num_descriptors;
    }

    ShaderStage operator|=(const ShaderStage lhs, const ShaderStage rhs) {
        return static_cast<ShaderStage>(static_cast<uint32_t>(lhs) | static_cast<uint32_t>(rhs));
    }

    bool is_depth_format(const PixelFormat format) {
        switch(format) {
            case PixelFormat::Rgba8:
                [[fallthrough]];
            case PixelFormat::Rgba16F:
                [[fallthrough]];
            case PixelFormat::Rgba32F:
                return false;

            case PixelFormat::Depth32:
                [[fallthrough]];
            case PixelFormat::Depth24Stencil8:
                return true;

            default:
                return false;
        }
    }

    uint32_t get_byte_size(const VertexFieldFormat format) {
        switch(format) {
            case VertexFieldFormat::Uint:
                return 4;

            case VertexFieldFormat::Float2:
                return 8;

            case VertexFieldFormat::Float3:
                return 12;

            case VertexFieldFormat::Float4:
                return 16;

            default:
                return 16;
        }
    }
} // namespace nova::renderer::rhi
<commit_msg>[rhi] Fix iterating over rx::vector<commit_after>#include "nova_renderer/rhi/rhi_types.hpp"

namespace nova::renderer::rhi {
    bool ResourceBindingDescription::operator==(const ResourceBindingDescription& other) {
        return set == other.set && binding == other.binding && count == other.count && type == other.type;
    }

    bool ResourceBindingDescription::operator!=(const ResourceBindingDescription& other) { return !(*this == other); }

    ResourceBarrier::ResourceBarrier() {}

    DescriptorResourceInfo::DescriptorResourceInfo() {}

    uint32_t PipelineInterface::get_num_descriptors_of_type(const DescriptorType type) const {
        uint32_t num_descriptors = 0;
        bindings.each_value([&](const ResourceBindingDescription& description) {
            if(description.type == type) {
                num_descriptors++;
            }
        });

        return num_descriptors;
    }

    ShaderStage operator|=(const ShaderStage lhs, const ShaderStage rhs) {
        return static_cast<ShaderStage>(static_cast<uint32_t>(lhs) | static_cast<uint32_t>(rhs));
    }

    bool is_depth_format(const PixelFormat format) {
        switch(format) {
            case PixelFormat::Rgba8:
                [[fallthrough]];
            case PixelFormat::Rgba16F:
                [[fallthrough]];
            case PixelFormat::Rgba32F:
                return false;

            case PixelFormat::Depth32:
                [[fallthrough]];
            case PixelFormat::Depth24Stencil8:
                return true;

            default:
                return false;
        }
    }

    uint32_t get_byte_size(const VertexFieldFormat format) {
        switch(format) {
            case VertexFieldFormat::Uint:
                return 4;

            case VertexFieldFormat::Float2:
                return 8;

            case VertexFieldFormat::Float3:
                return 12;

            case VertexFieldFormat::Float4:
                return 16;

            default:
                return 16;
        }
    }
} // namespace nova::renderer::rhi
<|endoftext|>