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

#include "main.h"
#include "db.h"
#include "init.h"
#include "freicoinrpc.h"

using namespace json_spirit;
using namespace std;

Value getgenerate(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getgenerate\n"
            "Returns true or false.");

    return GetBoolArg("-gen");
}

Value setgenerate(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 2)
        throw runtime_error(
            "setgenerate <generate> [genproclimit]\n"
            "<generate> is true or false to turn generation on or off.\n"
            "Generation is limited to [genproclimit] processors, -1 is unlimited.");

    bool fGenerate = true;
    if (params.size() > 0)
        fGenerate = params[0].get_bool();

    if (params.size() > 1)
    {
        int nGenProcLimit = params[1].get_int();
        mapArgs["-genproclimit"] = itostr(nGenProcLimit);
        if (nGenProcLimit == 0)
            fGenerate = false;
    }
    mapArgs["-gen"] = (fGenerate ? "1" : "0");

    GenerateFreicoins(fGenerate, pwalletMain);
    return Value::null;
}

Value gethashespersec(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "gethashespersec\n"
            "Returns a recent hashes per second performance measurement while generating.");

    if (GetTimeMillis() - nHPSTimerStart > 8000)
        return (boost::int64_t)0;
    return (boost::int64_t)dHashesPerSec;
}

Value getmininginfo(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getmininginfo\n"
            "Returns an object containing mining-related information.");

    Object obj;
    obj.push_back(Pair("blocks",        (int)nBestHeight));
    obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize));
    obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx));
    obj.push_back(Pair("difficulty",    (double)GetDifficulty()));
    obj.push_back(Pair("errors",        GetWarnings("statusbar")));
    obj.push_back(Pair("generate",      GetBoolArg("-gen")));
    obj.push_back(Pair("genproclimit",  (int)GetArg("-genproclimit", -1)));
    obj.push_back(Pair("hashespersec",  gethashespersec(params, false)));
    obj.push_back(Pair("pooledtx",      (uint64_t)mempool.size()));
    obj.push_back(Pair("testnet",       fTestNet));
    return obj;
}

Value getwork(const Array& params, bool fHelp)
{
    if (fHelp || params.size() > 1)
        throw runtime_error(
            "getwork [data]\n"
            "If [data] is not specified, returns formatted hash data to work on:\n"
            "  \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
            "  \"data\" : block data\n"
            "  \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
            "  \"target\" : little endian hash target\n"
            "If [data] is specified, tries to solve the block and returns true if it was successful.");

    if (vNodes.empty())
        throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Freicoin is not connected!");

    if (IsInitialBlockDownload())
        throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Freicoin is downloading blocks...");

    typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
    static mapNewBlock_t mapNewBlock;    // FIXME: thread safety
    static vector<CBlock*> vNewBlock;
    static CReserveKey reservekey(pwalletMain);

    if (params.size() == 0)
    {
        // Update block
        static unsigned int nTransactionsUpdatedLast;
        static CBlockIndex* pindexPrev;
        static int64 nStart;
        static CBlock* pblock;
        if (pindexPrev != pindexBest ||
            (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
        {
            if (pindexPrev != pindexBest)
            {
                // Deallocate old blocks since they're obsolete now
                mapNewBlock.clear();
                BOOST_FOREACH(CBlock* pblock, vNewBlock)
                    delete pblock;
                vNewBlock.clear();
            }

            // Clear pindexPrev so future getworks make a new block, despite any failures from here on
            pindexPrev = NULL;

            // Store the pindexBest used before CreateNewBlock, to avoid races
            nTransactionsUpdatedLast = nTransactionsUpdated;
            CBlockIndex* pindexPrevNew = pindexBest;
            nStart = GetTime();

            // Create new block
            pblock = CreateNewBlock(reservekey);
            if (!pblock)
                throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory");
            vNewBlock.push_back(pblock);

            // Need to update only after we know CreateNewBlock succeeded
            pindexPrev = pindexPrevNew;
        }

        // Update nTime
        pblock->UpdateTime(pindexPrev);
        pblock->nNonce = 0;

        // Update nExtraNonce
        static unsigned int nExtraNonce = 0;
        IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);

        // Save
        mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);

        // Pre-build hash buffers
        char pmidstate[32];
        char pdata[128];
        char phash1[64];
        FormatHashBuffers(pblock, pmidstate, pdata, phash1);

        uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();

        Object result;
        result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
        result.push_back(Pair("data",     HexStr(BEGIN(pdata), END(pdata))));
        result.push_back(Pair("hash1",    HexStr(BEGIN(phash1), END(phash1)))); // deprecated
        result.push_back(Pair("target",   HexStr(BEGIN(hashTarget), END(hashTarget))));
        return result;
    }
    else
    {
        // Parse parameters
        vector<unsigned char> vchData = ParseHex(params[0].get_str());
        if (vchData.size() != 128)
            throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
        CBlock* pdata = (CBlock*)&vchData[0];

        // Byte reverse
        for (int i = 0; i < 128/4; i++)
            ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);

        // Get saved block
        if (!mapNewBlock.count(pdata->hashMerkleRoot))
            return false;
        CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;

        pblock->nTime = pdata->nTime;
        pblock->nNonce = pdata->nNonce;
        pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
        pblock->hashMerkleRoot = pblock->BuildMerkleTree();

        return CheckWork(pblock, *pwalletMain, reservekey);
    }
}

Value getblocktemplate(const Array& params, bool fHelp)
{
    if (fHelp || params.size() > 1)
        throw runtime_error(
            "getblocktemplate [params]\n"
            "Returns data needed to construct a block to work on:\n"
            "  \"version\" : block version\n"
            "  \"previousblockhash\" : hash of current highest block\n"
            "  \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
            "  \"coinbaseaux\" : data that should be included in coinbase\n"
            "  \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
            "  \"budget\" : required outputs of the coinbase transaction"
            "  \"target\" : hash target\n"
            "  \"mintime\" : minimum timestamp appropriate for next block\n"
            "  \"curtime\" : current timestamp\n"
            "  \"mutable\" : list of ways the block template may be changed\n"
            "  \"noncerange\" : range of valid nonces\n"
            "  \"sigoplimit\" : limit of sigops in blocks\n"
            "  \"sizelimit\" : limit of block size\n"
            "  \"bits\" : compressed target of next block\n"
            "  \"height\" : height of the next block\n"
            "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.");

    std::string strMode = "template";
    if (params.size() > 0)
    {
        const Object& oparam = params[0].get_obj();
        const Value& modeval = find_value(oparam, "mode");
        if (modeval.type() == str_type)
            strMode = modeval.get_str();
        else if (modeval.type() == null_type)
        {
            /* Do nothing */
        }
        else
            throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode");
    }

    if (strMode != "template")
        throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode");

    if (vNodes.empty())
        throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Freicoin is not connected!");

    if (IsInitialBlockDownload())
        throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Freicoin is downloading blocks...");

    static CReserveKey reservekey(pwalletMain);

    // Update block
    static unsigned int nTransactionsUpdatedLast;
    static CBlockIndex* pindexPrev;
    static int64 nStart;
    static CBlock* pblock;
    if (pindexPrev != pindexBest ||
        (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
    {
        // Clear pindexPrev so future calls make a new block, despite any failures from here on
        pindexPrev = NULL;

        // Store the pindexBest used before CreateNewBlock, to avoid races
        nTransactionsUpdatedLast = nTransactionsUpdated;
        CBlockIndex* pindexPrevNew = pindexBest;
        nStart = GetTime();

        // Create new block
        if(pblock)
        {
            delete pblock;
            pblock = NULL;
        }
        pblock = CreateNewBlock(reservekey);
        if (!pblock)
            throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory");

        // Need to update only after we know CreateNewBlock succeeded
        pindexPrev = pindexPrevNew;
    }

    // Update nTime
    pblock->UpdateTime(pindexPrev);
    pblock->nNonce = 0;

    Array transactions;
    map<uint256, int64_t> setTxIndex;
    int i = 0;
    CTxDB txdb("r");
    BOOST_FOREACH (CTransaction& tx, pblock->vtx)
    {
        uint256 txHash = tx.GetHash();
        setTxIndex[txHash] = i++;

        if (tx.IsCoinBase())
            continue;

        Object entry;

        CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
        ssTx << tx;
        entry.push_back(Pair("data", HexStr(ssTx.begin(), ssTx.end())));

        entry.push_back(Pair("hash", txHash.GetHex()));

        MapPrevTx mapInputs;
        map<uint256, CTxIndex> mapUnused;
        bool fInvalid = false;
        if (tx.FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid))
        {
            mpq nFee = tx.GetValueIn(mapInputs) - tx.GetValueOut();
            entry.push_back(Pair("fee", FormatMoney(nFee)));

            Array deps;
            BOOST_FOREACH (MapPrevTx::value_type& inp, mapInputs)
            {
                if (setTxIndex.count(inp.first))
                    deps.push_back(setTxIndex[inp.first]);
            }
            entry.push_back(Pair("depends", deps));

            int64_t nSigOps = tx.GetLegacySigOpCount();
            nSigOps += tx.GetP2SHSigOpCount(mapInputs);
            entry.push_back(Pair("sigops", nSigOps));
        }

        transactions.push_back(entry);
    }

    Object aux;
    aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));

    uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();

    static Array aMutable;
    if (aMutable.empty())
    {
        aMutable.push_back("time");
        aMutable.push_back("transactions");
        aMutable.push_back("prevblock");
    }

    Object result;
    result.push_back(Pair("version", pblock->nVersion));
    result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
    result.push_back(Pair("transactions", transactions));
    result.push_back(Pair("coinbaseaux", aux));
    Array aBudget;
    BOOST_FOREACH(const CTxOut& txout, pblock->vtx[0].vout) {
        if ( txout != pblock->vtx[0].vout[0] ) {
            Object entry;
            CTxDestination addr;
            if ( ExtractDestination(txout.scriptPubKey, addr) )
                entry.push_back(Pair("address", CFreicoinAddress(addr).ToString()));
            else
                entry.push_back(Pair("script", txout.scriptPubKey.ToString()));
            entry.push_back(Pair("value", (int64_t)txout.nValue));
            aBudget.push_back(entry);
        }
    }
    result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
    result.push_back(Pair("budget", aBudget));
    result.push_back(Pair("target", hashTarget.GetHex()));
    result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
    result.push_back(Pair("mutable", aMutable));
    result.push_back(Pair("noncerange", "00000000ffffffff"));
    result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS));
    result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE));
    result.push_back(Pair("curtime", (int64_t)pblock->nTime));
    result.push_back(Pair("bits", HexBits(pblock->nBits)));
    result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1)));

    return result;
}

Value submitblock(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 2)
        throw runtime_error(
            "submitblock <hex data> [optional-params-obj]\n"
            "[optional-params-obj] parameter is currently ignored.\n"
            "Attempts to submit new block to network.\n"
            "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.");

    vector<unsigned char> blockData(ParseHex(params[0].get_str()));
    CDataStream ssBlock(blockData, SER_NETWORK, PROTOCOL_VERSION);
    CBlock block;
    try {
        ssBlock >> block;
    }
    catch (std::exception &e) {
        throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed");
    }

    bool fAccepted = ProcessBlock(NULL, &block);
    if (!fAccepted)
        return "rejected";

    return Value::null;
}

<commit_msg>Restructure output of 'budget' entry to match the output of the various gettransaction calls.<commit_after>// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "main.h"
#include "db.h"
#include "init.h"
#include "freicoinrpc.h"

using namespace json_spirit;
using namespace std;

extern void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out);

Value getgenerate(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getgenerate\n"
            "Returns true or false.");

    return GetBoolArg("-gen");
}

Value setgenerate(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 2)
        throw runtime_error(
            "setgenerate <generate> [genproclimit]\n"
            "<generate> is true or false to turn generation on or off.\n"
            "Generation is limited to [genproclimit] processors, -1 is unlimited.");

    bool fGenerate = true;
    if (params.size() > 0)
        fGenerate = params[0].get_bool();

    if (params.size() > 1)
    {
        int nGenProcLimit = params[1].get_int();
        mapArgs["-genproclimit"] = itostr(nGenProcLimit);
        if (nGenProcLimit == 0)
            fGenerate = false;
    }
    mapArgs["-gen"] = (fGenerate ? "1" : "0");

    GenerateFreicoins(fGenerate, pwalletMain);
    return Value::null;
}

Value gethashespersec(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "gethashespersec\n"
            "Returns a recent hashes per second performance measurement while generating.");

    if (GetTimeMillis() - nHPSTimerStart > 8000)
        return (boost::int64_t)0;
    return (boost::int64_t)dHashesPerSec;
}

Value getmininginfo(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getmininginfo\n"
            "Returns an object containing mining-related information.");

    Object obj;
    obj.push_back(Pair("blocks",        (int)nBestHeight));
    obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize));
    obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx));
    obj.push_back(Pair("difficulty",    (double)GetDifficulty()));
    obj.push_back(Pair("errors",        GetWarnings("statusbar")));
    obj.push_back(Pair("generate",      GetBoolArg("-gen")));
    obj.push_back(Pair("genproclimit",  (int)GetArg("-genproclimit", -1)));
    obj.push_back(Pair("hashespersec",  gethashespersec(params, false)));
    obj.push_back(Pair("pooledtx",      (uint64_t)mempool.size()));
    obj.push_back(Pair("testnet",       fTestNet));
    return obj;
}

Value getwork(const Array& params, bool fHelp)
{
    if (fHelp || params.size() > 1)
        throw runtime_error(
            "getwork [data]\n"
            "If [data] is not specified, returns formatted hash data to work on:\n"
            "  \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
            "  \"data\" : block data\n"
            "  \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
            "  \"target\" : little endian hash target\n"
            "If [data] is specified, tries to solve the block and returns true if it was successful.");

    if (vNodes.empty())
        throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Freicoin is not connected!");

    if (IsInitialBlockDownload())
        throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Freicoin is downloading blocks...");

    typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
    static mapNewBlock_t mapNewBlock;    // FIXME: thread safety
    static vector<CBlock*> vNewBlock;
    static CReserveKey reservekey(pwalletMain);

    if (params.size() == 0)
    {
        // Update block
        static unsigned int nTransactionsUpdatedLast;
        static CBlockIndex* pindexPrev;
        static int64 nStart;
        static CBlock* pblock;
        if (pindexPrev != pindexBest ||
            (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
        {
            if (pindexPrev != pindexBest)
            {
                // Deallocate old blocks since they're obsolete now
                mapNewBlock.clear();
                BOOST_FOREACH(CBlock* pblock, vNewBlock)
                    delete pblock;
                vNewBlock.clear();
            }

            // Clear pindexPrev so future getworks make a new block, despite any failures from here on
            pindexPrev = NULL;

            // Store the pindexBest used before CreateNewBlock, to avoid races
            nTransactionsUpdatedLast = nTransactionsUpdated;
            CBlockIndex* pindexPrevNew = pindexBest;
            nStart = GetTime();

            // Create new block
            pblock = CreateNewBlock(reservekey);
            if (!pblock)
                throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory");
            vNewBlock.push_back(pblock);

            // Need to update only after we know CreateNewBlock succeeded
            pindexPrev = pindexPrevNew;
        }

        // Update nTime
        pblock->UpdateTime(pindexPrev);
        pblock->nNonce = 0;

        // Update nExtraNonce
        static unsigned int nExtraNonce = 0;
        IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);

        // Save
        mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);

        // Pre-build hash buffers
        char pmidstate[32];
        char pdata[128];
        char phash1[64];
        FormatHashBuffers(pblock, pmidstate, pdata, phash1);

        uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();

        Object result;
        result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
        result.push_back(Pair("data",     HexStr(BEGIN(pdata), END(pdata))));
        result.push_back(Pair("hash1",    HexStr(BEGIN(phash1), END(phash1)))); // deprecated
        result.push_back(Pair("target",   HexStr(BEGIN(hashTarget), END(hashTarget))));
        return result;
    }
    else
    {
        // Parse parameters
        vector<unsigned char> vchData = ParseHex(params[0].get_str());
        if (vchData.size() != 128)
            throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
        CBlock* pdata = (CBlock*)&vchData[0];

        // Byte reverse
        for (int i = 0; i < 128/4; i++)
            ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);

        // Get saved block
        if (!mapNewBlock.count(pdata->hashMerkleRoot))
            return false;
        CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;

        pblock->nTime = pdata->nTime;
        pblock->nNonce = pdata->nNonce;
        pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
        pblock->hashMerkleRoot = pblock->BuildMerkleTree();

        return CheckWork(pblock, *pwalletMain, reservekey);
    }
}

Value getblocktemplate(const Array& params, bool fHelp)
{
    if (fHelp || params.size() > 1)
        throw runtime_error(
            "getblocktemplate [params]\n"
            "Returns data needed to construct a block to work on:\n"
            "  \"version\" : block version\n"
            "  \"previousblockhash\" : hash of current highest block\n"
            "  \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
            "  \"coinbaseaux\" : data that should be included in coinbase\n"
            "  \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
            "  \"budget\" : required outputs of the coinbase transaction"
            "  \"target\" : hash target\n"
            "  \"mintime\" : minimum timestamp appropriate for next block\n"
            "  \"curtime\" : current timestamp\n"
            "  \"mutable\" : list of ways the block template may be changed\n"
            "  \"noncerange\" : range of valid nonces\n"
            "  \"sigoplimit\" : limit of sigops in blocks\n"
            "  \"sizelimit\" : limit of block size\n"
            "  \"bits\" : compressed target of next block\n"
            "  \"height\" : height of the next block\n"
            "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.");

    std::string strMode = "template";
    if (params.size() > 0)
    {
        const Object& oparam = params[0].get_obj();
        const Value& modeval = find_value(oparam, "mode");
        if (modeval.type() == str_type)
            strMode = modeval.get_str();
        else if (modeval.type() == null_type)
        {
            /* Do nothing */
        }
        else
            throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode");
    }

    if (strMode != "template")
        throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode");

    if (vNodes.empty())
        throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Freicoin is not connected!");

    if (IsInitialBlockDownload())
        throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Freicoin is downloading blocks...");

    static CReserveKey reservekey(pwalletMain);

    // Update block
    static unsigned int nTransactionsUpdatedLast;
    static CBlockIndex* pindexPrev;
    static int64 nStart;
    static CBlock* pblock;
    if (pindexPrev != pindexBest ||
        (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
    {
        // Clear pindexPrev so future calls make a new block, despite any failures from here on
        pindexPrev = NULL;

        // Store the pindexBest used before CreateNewBlock, to avoid races
        nTransactionsUpdatedLast = nTransactionsUpdated;
        CBlockIndex* pindexPrevNew = pindexBest;
        nStart = GetTime();

        // Create new block
        if(pblock)
        {
            delete pblock;
            pblock = NULL;
        }
        pblock = CreateNewBlock(reservekey);
        if (!pblock)
            throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory");

        // Need to update only after we know CreateNewBlock succeeded
        pindexPrev = pindexPrevNew;
    }

    // Update nTime
    pblock->UpdateTime(pindexPrev);
    pblock->nNonce = 0;

    Array transactions;
    map<uint256, int64_t> setTxIndex;
    int i = 0;
    CTxDB txdb("r");
    BOOST_FOREACH (CTransaction& tx, pblock->vtx)
    {
        uint256 txHash = tx.GetHash();
        setTxIndex[txHash] = i++;

        if (tx.IsCoinBase())
            continue;

        Object entry;

        CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
        ssTx << tx;
        entry.push_back(Pair("data", HexStr(ssTx.begin(), ssTx.end())));

        entry.push_back(Pair("hash", txHash.GetHex()));

        MapPrevTx mapInputs;
        map<uint256, CTxIndex> mapUnused;
        bool fInvalid = false;
        if (tx.FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid))
        {
            mpq nFee = tx.GetValueIn(mapInputs) - tx.GetValueOut();
            entry.push_back(Pair("fee", FormatMoney(nFee)));

            Array deps;
            BOOST_FOREACH (MapPrevTx::value_type& inp, mapInputs)
            {
                if (setTxIndex.count(inp.first))
                    deps.push_back(setTxIndex[inp.first]);
            }
            entry.push_back(Pair("depends", deps));

            int64_t nSigOps = tx.GetLegacySigOpCount();
            nSigOps += tx.GetP2SHSigOpCount(mapInputs);
            entry.push_back(Pair("sigops", nSigOps));
        }

        transactions.push_back(entry);
    }

    Object aux;
    aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));

    uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();

    static Array aMutable;
    if (aMutable.empty())
    {
        aMutable.push_back("time");
        aMutable.push_back("transactions");
        aMutable.push_back("prevblock");
    }

    Object result;
    result.push_back(Pair("version", pblock->nVersion));
    result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
    result.push_back(Pair("transactions", transactions));
    result.push_back(Pair("coinbaseaux", aux));
    Array aBudget;
    BOOST_FOREACH(const CTxOut& txout, pblock->vtx[0].vout) {
        if ( txout != pblock->vtx[0].vout[0] ) {
            Object entry, script;
            ScriptPubKeyToJSON(txout.scriptPubKey, script);
            entry.push_back(Pair("scriptPubKey", script));
            entry.push_back(Pair("value", (int64_t)txout.nValue));
            aBudget.push_back(entry);
        }
    }
    result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
    result.push_back(Pair("budget", aBudget));
    result.push_back(Pair("target", hashTarget.GetHex()));
    result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
    result.push_back(Pair("mutable", aMutable));
    result.push_back(Pair("noncerange", "00000000ffffffff"));
    result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS));
    result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE));
    result.push_back(Pair("curtime", (int64_t)pblock->nTime));
    result.push_back(Pair("bits", HexBits(pblock->nBits)));
    result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1)));

    return result;
}

Value submitblock(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 2)
        throw runtime_error(
            "submitblock <hex data> [optional-params-obj]\n"
            "[optional-params-obj] parameter is currently ignored.\n"
            "Attempts to submit new block to network.\n"
            "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.");

    vector<unsigned char> blockData(ParseHex(params[0].get_str()));
    CDataStream ssBlock(blockData, SER_NETWORK, PROTOCOL_VERSION);
    CBlock block;
    try {
        ssBlock >> block;
    }
    catch (std::exception &e) {
        throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed");
    }

    bool fAccepted = ProcessBlock(NULL, &block);
    if (!fAccepted)
        return "rejected";

    return Value::null;
}

<|endoftext|>


<commit_before>{
   //
   // This macro displays the physical ROOT file structure
   //
   gROOT->Reset();
   c1 = new TCanvas("c1","ROOT File description",200,10,700,550);

   c1->Range(0,-0.25,21,14);
   TPaveLabel title(5,12,15,13.7,c1->GetTitle());
   title.SetFillColor(16);
   title.Draw();

   // horizonthal file layout
   TPave file(1,8.5,20,11);
   file.SetFillColor(11);
   file.Draw();
   TPave fileh(1,8.5,2.5,11);
   fileh.SetFillColor(44);
   fileh.Draw();
   TPave lrh(2.5,8.5,3.3,11,1);
   lrh.SetFillColor(33);
   lrh.Draw();
   lrh.DrawPave(6.9,8.5,7.7,11,1);
   lrh.DrawPave(10.5,8.5,11.3,11,1);
   lrh.DrawPave(14.5,8.5,15.3,11,1);
   TLine ldot(1,8.5,0.5,6.5);
   ldot.SetLineStyle(2);
   ldot.Draw();
   ldot.DrawLine(2.5, 8.5, 9.4, 6.5);
   ldot.DrawLine(10.5, 8.5, 10, 6.5);
   ldot.DrawLine(11.3, 8.5, 19.5, 6.5);
   TLine line(2.6,11,2.6,11.5);
   line.Draw();
   line.DrawLine(2.6,11.5,7,11.5);
   TArrow arrow(7,11.5,7,11.1,0.01,"|>");
   arrow.SetFillStyle(1001);
   arrow.Draw();
   line.DrawLine( 7, 8.5, 7, 8.0);
   line.DrawLine( 7, 8.0, 10.6, 8);
   arrow.DrawArrow( 10.6,8, 10.6, 8.4,0.01,"|>");
   line.DrawLine( 10.6, 11, 10.6, 11.5);
   line.DrawLine( 10.6, 11.5, 14.6, 11.5);
   arrow.DrawArrow( 14.6,11.5, 14.6,11.1,0.01,"|>");
   line.DrawLine( 14.6, 8.5, 14.6, 8.0);
   line.DrawLine( 14.6, 8.0, 16, 8);
   ldot.DrawLine(16, 8, 19, 8);
   TText vert(1.5,9.75,"File");
   vert.SetTextAlign(21);
   vert.SetTextAngle(90);
   vert.SetTextSize(0.025);
   vert.Draw();
   vert.DrawText(2.0, 9.75,"Header");
   vert.DrawText(2.9, 9.75,"Logical Record");
   vert.DrawText(3.2, 9.75,"Header");
   vert.DrawText(7.3, 9.75,"Logical Record");
   vert.DrawText(7.6, 9.75,"Header");
   vert.DrawText(10.9,9.75,"Logical Record");
   vert.DrawText(11.2,9.75,"Header");
   vert.DrawText(14.9,9.75,"Logical Record");
   vert.DrawText(15.2,9.75,"Header");
   TText hori(4.75,10,"Object");
   hori.SetTextAlign(22);
   hori.SetTextSize(0.035);
   hori.Draw();
   hori.DrawText(4.75, 9.5,"Data");
   hori.DrawText(9.2, 10,"Deleted");
   hori.DrawText(9.2, 9.5,"Object");
   line.DrawLine( 6.9, 8.5, 10.5, 11);
   line.DrawLine( 6.9, 11, 10.5, 8.5);
   TText tbig(17,9.75,"............");
   tbig.SetTextAlign(22);
   tbig.SetTextSize(0.03);
   tbig.Draw();
   tbig.DrawText(2.6, 7, "fBEGIN");
   tbig.DrawText(20., 7, "fEND");
   arrow.DrawArrow( 2.6,7, 2.6,8.4,0.01,"|>");
   arrow.DrawArrow( 20,7, 20,8.4,0.01,"|>");

   //file header
   TPaveText header(0.5,.2,9.4,6.5);
   header.SetFillColor(44);
   header.Draw();
   TText *fh=header.AddText("File Header");
   fh->SetTextAlign(23);
   fh->SetTextSize(0.04);
   header.SetTextSize(0.027);
   header.SetTextAlign(12);
   header.AddText(" ");
   header.AddLine(0,0,0,0);
   header.AddText("\"root\": Root File Identifier");
   header.AddText("fVersion: File version identifier");
   header.AddText("fBEGIN: Pointer to first data record");
   header.AddText("fEND: Pointer to first free word at EOF");
   header.AddText("fSeekFree: Pointer to FREE data record");
   header.AddText("fNbytesFree: Number of bytes in FREE");
   header.AddText("fNfree: Number of free data records");
   header.AddText("fNbytesName: Number of bytes in name/title");
   header.AddText("fUnits: Number of bytes for pointers");
   header.AddText("fCompress: Compression level");

   //logical record header
   TPaveText lrecord(10,0.2,19.5,6.5);
   lrecord.SetFillColor(33);
   lrecord.Draw();
   TText *tlrh=lrecord.AddText("Logical Record Header (TKEY)");
   tlrh->SetTextAlign(23);
   tlrh->SetTextSize(0.04);
   lrecord.SetTextSize(0.027);
   lrecord.SetTextAlign(12);
   lrecord.AddText(" ");
   lrecord.AddLine(0,0,0,0);
   lrecord.AddText("fNbytes: Length of compressed object");
   lrecord.AddText("fVersion: Key version identifier");
   lrecord.AddText("fObjLen: Length of uncompressed object");
   lrecord.AddText("fDatime: Date/Time when written to store");
   lrecord.AddText("fKeylen: Number of bytes for the key");
   lrecord.AddText("fCycle : Cycle number");
   lrecord.AddText("fSeekKey: Pointer to object on file");
   lrecord.AddText("fSeekPdir: Pointer to directory on file");
   lrecord.AddText("fClassName: class name of the object");
   lrecord.AddText("fName: name of the object");
   lrecord.AddText("fTitle: title of the object");

   c1->Update();
}
<commit_msg>header text was not properly placed (showed more clearly with new TTF implementation). By Olivier.<commit_after>{
   //
   // This macro displays the physical ROOT file structure
   //
   gROOT->Reset();
   c1 = new TCanvas("c1","ROOT File description",200,10,700,550);

   c1->Range(0,-0.25,21,14);
   TPaveLabel title(5,12,15,13.7,c1->GetTitle());
   title.SetFillColor(16);
   title.Draw();

   // horizonthal file layout
   TPave file(1,8.5,20,11);
   file.SetFillColor(11);
   file.Draw();
   TPave fileh(1,8.5,2.5,11);
   fileh.SetFillColor(44);
   fileh.Draw();
   TPave lrh(2.5,8.5,3.3,11,1);
   lrh.SetFillColor(33);
   lrh.Draw();
   lrh.DrawPave(6.9,8.5,7.7,11,1);
   lrh.DrawPave(10.5,8.5,11.3,11,1);
   lrh.DrawPave(14.5,8.5,15.3,11,1);
   TLine ldot(1,8.5,0.5,6.5);
   ldot.SetLineStyle(2);
   ldot.Draw();
   ldot.DrawLine(2.5, 8.5, 9.4, 6.5);
   ldot.DrawLine(10.5, 8.5, 10, 6.5);
   ldot.DrawLine(11.3, 8.5, 19.5, 6.5);
   TLine line(2.6,11,2.6,11.5);
   line.Draw();
   line.DrawLine(2.6,11.5,7,11.5);
   TArrow arrow(7,11.5,7,11.1,0.01,"|>");
   arrow.SetFillStyle(1001);
   arrow.Draw();
   line.DrawLine( 7, 8.5, 7, 8.0);
   line.DrawLine( 7, 8.0, 10.6, 8);
   arrow.DrawArrow( 10.6,8, 10.6, 8.4,0.01,"|>");
   line.DrawLine( 10.6, 11, 10.6, 11.5);
   line.DrawLine( 10.6, 11.5, 14.6, 11.5);
   arrow.DrawArrow( 14.6,11.5, 14.6,11.1,0.01,"|>");
   line.DrawLine( 14.6, 8.5, 14.6, 8.0);
   line.DrawLine( 14.6, 8.0, 16, 8);
   ldot.DrawLine(16, 8, 19, 8);
   TText vert(1.5,9.75,"File");
   vert.SetTextAlign(21);
   vert.SetTextAngle(90);
   vert.SetTextSize(0.025);
   vert.Draw();
   vert.DrawText(2.0, 9.75,"Header");
   vert.DrawText(2.9, 9.75,"Logical Record");
   vert.DrawText(3.2, 9.75,"Header");
   vert.DrawText(7.3, 9.75,"Logical Record");
   vert.DrawText(7.6, 9.75,"Header");
   vert.DrawText(10.9,9.75,"Logical Record");
   vert.DrawText(11.2,9.75,"Header");
   vert.DrawText(14.9,9.75,"Logical Record");
   vert.DrawText(15.2,9.75,"Header");
   TText hori(4.75,10,"Object");
   hori.SetTextAlign(22);
   hori.SetTextSize(0.035);
   hori.Draw();
   hori.DrawText(4.75, 9.5,"Data");
   hori.DrawText(9.2, 10,"Deleted");
   hori.DrawText(9.2, 9.5,"Object");
   line.DrawLine( 6.9, 8.5, 10.5, 11);
   line.DrawLine( 6.9, 11, 10.5, 8.5);
   TText tbig(17,9.75,"............");
   tbig.SetTextAlign(22);
   tbig.SetTextSize(0.03);
   tbig.Draw();
   tbig.DrawText(2.6, 7, "fBEGIN");
   tbig.DrawText(20., 7, "fEND");
   arrow.DrawArrow( 2.6,7, 2.6,8.4,0.01,"|>");
   arrow.DrawArrow( 20,7, 20,8.4,0.01,"|>");

   //file header
   TPaveText header(0.5,.2,9.4,6.5);
   header.SetFillColor(44);
   header.Draw();
   TText *fh=header.AddText("File Header");
   fh->SetTextAlign(22);
   fh->SetTextSize(0.04);
   header.SetTextSize(0.027);
   header.SetTextAlign(12);
   header.AddText(" ");
   header.AddLine(0,0,0,0);
   header.AddText("\"root\": Root File Identifier");
   header.AddText("fVersion: File version identifier");
   header.AddText("fBEGIN: Pointer to first data record");
   header.AddText("fEND: Pointer to first free word at EOF");
   header.AddText("fSeekFree: Pointer to FREE data record");
   header.AddText("fNbytesFree: Number of bytes in FREE");
   header.AddText("fNfree: Number of free data records");
   header.AddText("fNbytesName: Number of bytes in name/title");
   header.AddText("fUnits: Number of bytes for pointers");
   header.AddText("fCompress: Compression level");

   //logical record header
   TPaveText lrecord(10,0.2,19.5,6.5);
   lrecord.SetFillColor(33);
   lrecord.Draw();
   TText *tlrh=lrecord.AddText("Logical Record Header (TKEY)");
   tlrh->SetTextAlign(22);
   tlrh->SetTextSize(0.04);
   lrecord.SetTextSize(0.027);
   lrecord.SetTextAlign(12);
   lrecord.AddText(" ");
   lrecord.AddLine(0,0,0,0);
   lrecord.AddText("fNbytes: Length of compressed object");
   lrecord.AddText("fVersion: Key version identifier");
   lrecord.AddText("fObjLen: Length of uncompressed object");
   lrecord.AddText("fDatime: Date/Time when written to store");
   lrecord.AddText("fKeylen: Number of bytes for the key");
   lrecord.AddText("fCycle : Cycle number");
   lrecord.AddText("fSeekKey: Pointer to object on file");
   lrecord.AddText("fSeekPdir: Pointer to directory on file");
   lrecord.AddText("fClassName: class name of the object");
   lrecord.AddText("fName: name of the object");
   lrecord.AddText("fTitle: title of the object");

   c1->Update();
}
<|endoftext|>


<commit_before>/**
 * \ file GainCompressorFilter.cpp
 */

#include <ATK/Dynamic/GainCompressorFilter.h>

#include <ATK/Core/InPointerFilter.h>
#include <ATK/Core/OutPointerFilter.h>

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_NO_MAIN
#include <boost/test/unit_test.hpp>

#include <boost/math/constants/constants.hpp>

#define PROCESSSIZE (64)

BOOST_AUTO_TEST_CASE( GainCompressorFilter_const_1_test )
{
  std::array<float, PROCESSSIZE> data;
  for(ptrdiff_t i = 0; i < PROCESSSIZE; ++i)
  {
    data[i] = 1;
  }

  ATK::InPointerFilter<float> generator(data.data(), 1, PROCESSSIZE, false);
  generator.set_output_sampling_rate(48000);

  std::array<float, PROCESSSIZE> outdata;

  ATK::GainFilter<ATK::GainCompressorFilter<float>> filter(1);
  filter.set_input_sampling_rate(48000);
  filter.set_input_port(0, &generator, 0);
  filter.set_threshold(10);

  ATK::OutPointerFilter<float> output(outdata.data(), 1, PROCESSSIZE, false);
  output.set_input_sampling_rate(48000);
  output.set_input_port(0, &filter, 0);

  output.process(PROCESSSIZE);

  for(ptrdiff_t i = 0; i < PROCESSSIZE; ++i)
  {
    BOOST_REQUIRE_CLOSE(1, outdata[i], 0.1);
  }
}

BOOST_AUTO_TEST_CASE( GainCompressorFilter_const_0_test )
{
  std::array<float, PROCESSSIZE> data;
  for(ptrdiff_t i = 0; i < PROCESSSIZE; ++i)
  {
    data[i] = 0;
  }

  ATK::InPointerFilter<float> generator(data.data(), 1, PROCESSSIZE, false);
  generator.set_output_sampling_rate(48000);

  std::array<float, PROCESSSIZE> outdata;

  ATK::GainFilter<ATK::GainCompressorFilter<float>> filter(1);
  filter.set_input_sampling_rate(48000);
  filter.set_input_port(0, &generator, 0);

  ATK::OutPointerFilter<float> output(outdata.data(), 1, PROCESSSIZE, false);
  output.set_input_sampling_rate(48000);
  output.set_input_port(0, &filter, 0);

  output.process(PROCESSSIZE);

  for(ptrdiff_t i = 0; i < PROCESSSIZE; ++i)
  {
    BOOST_REQUIRE_CLOSE(1, outdata[i], 0.1); // if input is zero, we still need a gain of 1 to have a progression of 1 for values < threshold
  }
}

BOOST_AUTO_TEST_CASE( GainCompressorFilter_const_1_threshold_05_ratio_2_test )
{
  std::array<float, PROCESSSIZE> data;
  for(ptrdiff_t i = 0; i < PROCESSSIZE; ++i)
  {
    data[i] = 1;
  }

  ATK::InPointerFilter<float> generator(data.data(), 1, PROCESSSIZE, false);
  generator.set_output_sampling_rate(48000);

  std::array<float, PROCESSSIZE> outdata;

  ATK::GainFilter<ATK::GainCompressorFilter<float>> filter(1);
  filter.set_input_sampling_rate(48000);
  filter.set_input_port(0, &generator, 0);
  filter.set_threshold(0.5);
  filter.set_ratio(2);
  filter.set_softness(1);

  ATK::OutPointerFilter<float> output(outdata.data(), 1, PROCESSSIZE, false);
  output.set_input_sampling_rate(48000);
  output.set_input_port(0, &filter, 0);

  output.process(PROCESSSIZE);

  for(ptrdiff_t i = 0; i < PROCESSSIZE; ++i)
  {
    BOOST_REQUIRE_CLOSE(0.836990654, outdata[i], 0.1);
  }
}

BOOST_AUTO_TEST_CASE( GainCompressorFilter_const_1_threshold_05_ratio_4_test )
{
  std::array<float, PROCESSSIZE> data;
  for(ptrdiff_t i = 0; i < PROCESSSIZE; ++i)
  {
    data[i] = 1;
  }

  ATK::InPointerFilter<float> generator(data.data(), 1, PROCESSSIZE, false);
  generator.set_output_sampling_rate(48000);

  std::array<float, PROCESSSIZE> outdata;

  ATK::GainFilter<ATK::GainCompressorFilter<float>> filter(1);
  filter.set_input_sampling_rate(48000);
  filter.set_input_port(0, &generator, 0);
  filter.set_threshold(0.5);
  filter.set_ratio(4);
  filter.set_softness(1);

  ATK::OutPointerFilter<float> output(outdata.data(), 1, PROCESSSIZE, false);
  output.set_input_sampling_rate(48000);
  output.set_input_port(0, &filter, 0);

  output.process(PROCESSSIZE);

  for(ptrdiff_t i = 0; i < PROCESSSIZE; ++i)
  {
    BOOST_REQUIRE_CLOSE(0.765739262, outdata[i], 0.1);
  }
}
<commit_msg>Adding tests for threshold and ratio<commit_after>/**
 * \ file GainCompressorFilter.cpp
 */

#include <ATK/Dynamic/GainCompressorFilter.h>

#include <ATK/Core/InPointerFilter.h>
#include <ATK/Core/OutPointerFilter.h>

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_NO_MAIN
#include <boost/test/unit_test.hpp>

#include <boost/math/constants/constants.hpp>

const size_t PROCESSSIZE = 64;

BOOST_AUTO_TEST_CASE( GainFilter_threshold_test )
{
  ATK::GainFilter<ATK::GainCompressorFilter<float>> filter;
  filter.set_threshold(10);
  BOOST_CHECK_EQUAL(filter.get_threshold(), 10);
}

BOOST_AUTO_TEST_CASE( GainFilter_threshold_db_test )
{
  ATK::GainFilter<ATK::GainCompressorFilter<float>> filter;
  filter.set_threshold_db(20);
  BOOST_CHECK_EQUAL(filter.get_threshold(), 100);
}

BOOST_AUTO_TEST_CASE( GainFilter_threshold_range_test )
{
  ATK::GainFilter<ATK::GainCompressorFilter<float>> filter;
  BOOST_CHECK_THROW(filter.set_threshold(0), std::out_of_range);
}

BOOST_AUTO_TEST_CASE( GainFilter_ratio_test )
{
  ATK::GainFilter<ATK::GainCompressorFilter<float>> filter;
  filter.set_ratio(10);
  BOOST_CHECK_EQUAL(filter.get_ratio(), 10);
}

BOOST_AUTO_TEST_CASE( GainFilter_ratio_range_test )
{
  ATK::GainFilter<ATK::GainCompressorFilter<float>> filter;
  BOOST_CHECK_THROW(filter.set_ratio(0), std::out_of_range);
}

BOOST_AUTO_TEST_CASE( GainCompressorFilter_const_1_test )
{
  std::array<float, PROCESSSIZE> data;
  for(ptrdiff_t i = 0; i < PROCESSSIZE; ++i)
  {
    data[i] = 1;
  }

  ATK::InPointerFilter<float> generator(data.data(), 1, PROCESSSIZE, false);
  generator.set_output_sampling_rate(48000);

  std::array<float, PROCESSSIZE> outdata;

  ATK::GainFilter<ATK::GainCompressorFilter<float>> filter;
  filter.set_input_sampling_rate(48000);
  filter.set_input_port(0, &generator, 0);
  filter.set_threshold(10);

  ATK::OutPointerFilter<float> output(outdata.data(), 1, PROCESSSIZE, false);
  output.set_input_sampling_rate(48000);
  output.set_input_port(0, &filter, 0);

  output.process(PROCESSSIZE);

  for(ptrdiff_t i = 0; i < PROCESSSIZE; ++i)
  {
    BOOST_REQUIRE_CLOSE(1, outdata[i], 0.1);
  }
}

BOOST_AUTO_TEST_CASE( GainCompressorFilter_const_0_test )
{
  std::array<float, PROCESSSIZE> data;
  for(ptrdiff_t i = 0; i < PROCESSSIZE; ++i)
  {
    data[i] = 0;
  }

  ATK::InPointerFilter<float> generator(data.data(), 1, PROCESSSIZE, false);
  generator.set_output_sampling_rate(48000);

  std::array<float, PROCESSSIZE> outdata;

  ATK::GainFilter<ATK::GainCompressorFilter<float>> filter(1);
  filter.set_input_sampling_rate(48000);
  filter.set_input_port(0, &generator, 0);

  ATK::OutPointerFilter<float> output(outdata.data(), 1, PROCESSSIZE, false);
  output.set_input_sampling_rate(48000);
  output.set_input_port(0, &filter, 0);

  output.process(PROCESSSIZE);

  for(ptrdiff_t i = 0; i < PROCESSSIZE; ++i)
  {
    BOOST_REQUIRE_CLOSE(1, outdata[i], 0.1); // if input is zero, we still need a gain of 1 to have a progression of 1 for values < threshold
  }
}

BOOST_AUTO_TEST_CASE( GainCompressorFilter_const_1_threshold_05_ratio_2_test )
{
  std::array<float, PROCESSSIZE> data;
  for(ptrdiff_t i = 0; i < PROCESSSIZE; ++i)
  {
    data[i] = 1;
  }

  ATK::InPointerFilter<float> generator(data.data(), 1, PROCESSSIZE, false);
  generator.set_output_sampling_rate(48000);

  std::array<float, PROCESSSIZE> outdata;

  ATK::GainFilter<ATK::GainCompressorFilter<float>> filter(1);
  filter.set_input_sampling_rate(48000);
  filter.set_input_port(0, &generator, 0);
  filter.set_threshold(0.5);
  filter.set_ratio(2);
  filter.set_softness(1);

  ATK::OutPointerFilter<float> output(outdata.data(), 1, PROCESSSIZE, false);
  output.set_input_sampling_rate(48000);
  output.set_input_port(0, &filter, 0);

  output.process(PROCESSSIZE);

  for(ptrdiff_t i = 0; i < PROCESSSIZE; ++i)
  {
    BOOST_REQUIRE_CLOSE(0.836990654, outdata[i], 0.1);
  }
}

BOOST_AUTO_TEST_CASE( GainCompressorFilter_const_1_threshold_05_ratio_4_test )
{
  std::array<float, PROCESSSIZE> data;
  for(ptrdiff_t i = 0; i < PROCESSSIZE; ++i)
  {
    data[i] = 1;
  }

  ATK::InPointerFilter<float> generator(data.data(), 1, PROCESSSIZE, false);
  generator.set_output_sampling_rate(48000);

  std::array<float, PROCESSSIZE> outdata;

  ATK::GainFilter<ATK::GainCompressorFilter<float>> filter(1);
  filter.set_input_sampling_rate(48000);
  filter.set_input_port(0, &generator, 0);
  filter.set_threshold(0.5);
  filter.set_ratio(4);
  filter.set_softness(1);

  ATK::OutPointerFilter<float> output(outdata.data(), 1, PROCESSSIZE, false);
  output.set_input_sampling_rate(48000);
  output.set_input_port(0, &filter, 0);

  output.process(PROCESSSIZE);

  for(ptrdiff_t i = 0; i < PROCESSSIZE; ++i)
  {
    BOOST_REQUIRE_CLOSE(0.765739262, outdata[i], 0.1);
  }
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    CellularSegmentation1.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

// Software Guide : BeginLatex
//
// \index{itk::bio::CellularAggregate}
//
// The following example illustrates the use of Cellular Algorithms for performing image segmentation.
// Cellular algorithms are implemented by combining the following classes
//
// \subdoxygen{bio}{CellularAggregate}
// \subdoxygen{bio}{Cell}
//
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
#include "itkBioCellularAggregate.h"
#include "itkBioCell.h"
// Software Guide : EndCodeSnippet

#include "itkImage.h"
#include "itkImageFileReader.h"

int main( int argc, char *argv[] )
{
  if( argc < 7 )
    {
    std::cerr << "Missing Parameters " << std::endl;
    std::cerr << "Usage: " << argv[0];
    std::cerr << " inputImage  seedX seedY lowThreshold highThreshold iterations" << std::endl;
    return 1;
    }

  //  Software Guide : BeginLatex
  //
  //  We now define the image type using a pixel type and a particular
  //  dimension. In this case the \code{float} type is used for the pixels due
  //  to the requirements of the smoothing filter.
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  typedef   float           InternalPixelType;
  const     unsigned int    Dimension = 2;
  typedef itk::Image< InternalPixelType, Dimension >  ImageType;
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  The \subdoxygen{bio}{CellularAggregate} class must be instantiated using
  //  the dimension of the image to be segmented.
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  typedef itk::bio::CellularAggregate< Dimension >  CellularAggregateType;
  typedef CellularAggregateType::BioCellType        CellType;
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  Then an object of this class can be constructed by invoking the
  //  \code{New} operator and receiving the result in a \code{SmartPointer},
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  CellularAggregateType::Pointer cellularAggregate = CellularAggregateType::New();
  // Software Guide : EndCodeSnippet

  // We instantiate reader and writer types
  typedef  itk::ImageFileReader< ImageType > ReaderType;
  ReaderType::Pointer reader = ReaderType::New();
  reader->SetFileName( argv[1] );

  try
    {
    reader->Update();
    }
  catch( itk::ExceptionObject & excep )
    {
    std::cerr << "Exception caught !" << std::endl;
    std::cerr << excep << std::endl;
    }

  //  Software Guide : BeginLatex
  //
  //  The CellularAggregate considers the image as a chemical substrate in
  //  which the Cells are going to develop.  The intensity values of the image
  //  will influence the behavior of the Cells, in particular they will
  //  intervine to regulate the Cell Cycle. A Cellular Aggregate could be
  //  gathering information from several images simultaneously, in this context
  //  each image can bee seen as a map of concentration of a particular
  //  chemical compound. The set of images will describe the chemical
  //  composition of the extra cellular matrix.
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  cellularAggregate->AddSubstrate( reader->GetOutput() );
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  The initialization of the algorithm requires the user to provide a seed
  //  point. It is convenient to select this point to be placed in a
  //  \emph{typical} region of the anatomical structure to be segmented. A
  //  small neighborhood around the seed point will be used to compute the
  //  initial mean and standard deviation for the inclusion criterion. The
  //  seed is passed in the form of a \doxygen{Index} to the \code{SetSeed()}
  //  method.
  //
  //  \index{itk::ConfidenceConnectedImageFilter!SetSeed()}
  //  \index{itk::ConfidenceConnectedImageFilter!SetInitialNeighborhoodRadius()}
  //
  //  Software Guide : EndLatex

  ImageType::IndexType  index;

  index[0] = atoi( argv[2] );
  index[1] = atoi( argv[3] );

  CellType::PointType  position;

  reader->GetOutput()->TransformIndexToPhysicalPoint( index, position );

  //  Software Guide : BeginLatex
  //
  //  Individual Cell do not derive from the \doxygen{Object} class in order to
  //  avoid the penalties of Mutex operations when passing pointers to them.
  //  The Creation of a new cell is done by invoking the normal \code{new}
  //  operator.
  //
  //  \index{itk::bio::Cell!Creation}
  //  \index{itk::bio::Cell!pointer}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  CellType * egg = new CellType;
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  In this particular example, the Cell cycle is going to be controled
  //  mostly by the intensity values of the image.  These values are asimilated
  //  to concentrations of a particular chemical compound. Cell will feel
  //  compfortable at when the concentration of this chemical is inside a
  //  particular range. In this circumstances cells will be able to
  //  proliferate.  When the chemical concentration is out of the range, cell
  //  will not enter their division stage and will anchor to the cellular
  //  matrix. The values defining this range can be set by invoking the methods
  //  \code{SetChemoAttractantHighThreshold} and
  //  \code{SetChemoAttractantLowThreshold). These to methods are static and
  //  set the values to be used by all the cells.
  //
  //  \index{itk::bio::Cell!SetChemoAttractantLowThreshold}
  //  \index{itk::bio::Cell!SetChemoAttractantHighThreshold}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  CellType::SetChemoAttractantLowThreshold(  atof( argv[4] ) );
  CellType::SetChemoAttractantHighThreshold( atof( argv[5] ) );
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  The newly created Cell is passed to the \code{CellularAggregate} object
  //  that will take care of controling the development of the cells.
  //
  //  \index{itk::bio::CellularAggregate!SetEgg}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  cellularAggregate->SetEgg( egg, position );
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  The CellularAggregate will update the life cycle of all the cells in an
  //  iterative way.  The User must select how many iterations to run.
  //  CellularAlgorithms can in principle run forever. It is up to the User to
  //  define an stopping criterion. One of the simplest options is to set a
  //  limit to the number of iterations, by invoking the AdvanceTimeStep()
  //  method inside a for loop.
  //
  //  \index{itk::bio::CellularAggregate!SetEgg}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  unsigned int numberOfIterations = atoi( argv[6] );

  for(unsigned int i=0; i<numberOfIterations; i++)
    {
    cellularAggregate->AdvanceTimeStep();
    }
  // Software Guide : EndCodeSnippet

  return 0;
}

<commit_msg>BUG: Cells should only be created by CreateEgg() (only one), the Cellular      Aggregate takes care of replication. The Cell() constructor is now      protected in order to enforce this rule.<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    CellularSegmentation1.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

// Software Guide : BeginLatex
//
// \index{itk::bio::CellularAggregate}
//
// The following example illustrates the use of Cellular Algorithms for performing image segmentation.
// Cellular algorithms are implemented by combining the following classes
//
// \subdoxygen{bio}{CellularAggregate}
// \subdoxygen{bio}{Cell}
//
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
#include "itkBioCellularAggregate.h"
#include "itkBioCell.h"
// Software Guide : EndCodeSnippet

#include "itkImage.h"
#include "itkImageFileReader.h"

int main( int argc, char *argv[] )
{
  if( argc < 7 )
    {
    std::cerr << "Missing Parameters " << std::endl;
    std::cerr << "Usage: " << argv[0];
    std::cerr << " inputImage  seedX seedY lowThreshold highThreshold iterations" << std::endl;
    return 1;
    }

  //  Software Guide : BeginLatex
  //
  //  We now define the image type using a pixel type and a particular
  //  dimension. In this case the \code{float} type is used for the pixels due
  //  to the requirements of the smoothing filter.
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  typedef   float           InternalPixelType;
  const     unsigned int    Dimension = 2;
  typedef itk::Image< InternalPixelType, Dimension >  ImageType;
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  The \subdoxygen{bio}{CellularAggregate} class must be instantiated using
  //  the dimension of the image to be segmented.
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  typedef itk::bio::CellularAggregate< Dimension >  CellularAggregateType;
  typedef CellularAggregateType::BioCellType        CellType;
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  Then an object of this class can be constructed by invoking the
  //  \code{New} operator and receiving the result in a \code{SmartPointer},
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  CellularAggregateType::Pointer cellularAggregate = CellularAggregateType::New();
  // Software Guide : EndCodeSnippet

  // We instantiate reader and writer types
  typedef  itk::ImageFileReader< ImageType > ReaderType;
  ReaderType::Pointer reader = ReaderType::New();
  reader->SetFileName( argv[1] );

  std::cout << "Filename = " << argv[1] << std::endl;

  try
    {
    reader->Update();
    }
  catch( itk::ExceptionObject & excep )
    {
    std::cerr << "Exception caught !" << std::endl;
    std::cerr << excep << std::endl;
    }

  //  Software Guide : BeginLatex
  //
  //  The CellularAggregate considers the image as a chemical substrate in
  //  which the Cells are going to develop.  The intensity values of the image
  //  will influence the behavior of the Cells, in particular they will
  //  intervine to regulate the Cell Cycle. A Cellular Aggregate could be
  //  gathering information from several images simultaneously, in this context
  //  each image can bee seen as a map of concentration of a particular
  //  chemical compound. The set of images will describe the chemical
  //  composition of the extra cellular matrix.
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  cellularAggregate->AddSubstrate( reader->GetOutput() );
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  The initialization of the algorithm requires the user to provide a seed
  //  point. It is convenient to select this point to be placed in a
  //  \emph{typical} region of the anatomical structure to be segmented. A
  //  small neighborhood around the seed point will be used to compute the
  //  initial mean and standard deviation for the inclusion criterion. The
  //  seed is passed in the form of a \doxygen{Index} to the \code{SetSeed()}
  //  method.
  //
  //  \index{itk::ConfidenceConnectedImageFilter!SetSeed()}
  //  \index{itk::ConfidenceConnectedImageFilter!SetInitialNeighborhoodRadius()}
  //
  //  Software Guide : EndLatex

  ImageType::IndexType  index;

  index[0] = atoi( argv[2] );
  index[1] = atoi( argv[3] );

  CellType::PointType  position;

  reader->GetOutput()->TransformIndexToPhysicalPoint( index, position );

  std::cout << "Egg position index = " <<  index   << std::endl;
  std::cout << "Egg position point = " << position << std::endl;

  //  Software Guide : BeginLatex
  //
  //  Individual Cell do not derive from the \doxygen{Object} class in order to
  //  avoid the penalties of Mutex operations when passing pointers to them.
  //  The Creation of a new cell is done by invoking the normal \code{new}
  //  operator.
  //
  //  \index{itk::bio::Cell!Creation}
  //  \index{itk::bio::Cell!pointer}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  CellType * egg = CellType::CreateEgg();
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  In this particular example, the Cell cycle is going to be controled
  //  mostly by the intensity values of the image.  These values are asimilated
  //  to concentrations of a particular chemical compound. Cell will feel
  //  compfortable at when the concentration of this chemical is inside a
  //  particular range. In this circumstances cells will be able to
  //  proliferate.  When the chemical concentration is out of the range, cell
  //  will not enter their division stage and will anchor to the cellular
  //  matrix. The values defining this range can be set by invoking the methods
  //  \code{SetChemoAttractantHighThreshold} and
  //  \code{SetChemoAttractantLowThreshold). These to methods are static and
  //  set the values to be used by all the cells.
  //
  //  \index{itk::bio::Cell!SetChemoAttractantLowThreshold}
  //  \index{itk::bio::Cell!SetChemoAttractantHighThreshold}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  CellType::SetChemoAttractantLowThreshold(  atof( argv[4] ) );
  CellType::SetChemoAttractantHighThreshold( atof( argv[5] ) );
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  The newly created Cell is passed to the \code{CellularAggregate} object
  //  that will take care of controling the development of the cells.
  //
  //  \index{itk::bio::CellularAggregate!SetEgg}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  cellularAggregate->SetEgg( egg, position );
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  The CellularAggregate will update the life cycle of all the cells in an
  //  iterative way.  The User must select how many iterations to run.
  //  CellularAlgorithms can in principle run forever. It is up to the User to
  //  define an stopping criterion. One of the simplest options is to set a
  //  limit to the number of iterations, by invoking the AdvanceTimeStep()
  //  method inside a for loop.
  //
  //  \index{itk::bio::CellularAggregate!SetEgg}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  unsigned int numberOfIterations = atoi( argv[6] );

  std::cout << "numberOfIterations " << numberOfIterations << std::endl;

  for(unsigned int i=0; i<numberOfIterations; i++)
    {
    cellularAggregate->AdvanceTimeStep();
    }
  // Software Guide : EndCodeSnippet

  std::cout << " Final number of Cells = " << cellularAggregate->GetNumberOfCells() << std::endl;

  return 0;
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015-2018 Dubalu LLC. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "udp.h"

#include <arpa/inet.h>              // for inet_addr, htonl, htons
#include <cstring>                  // for memset
#include <errno.h>                  // for errno
#include <utility>
#include <fcntl.h>                  // for fcntl, F_GETFL, F_SETFL, O_NONBLOCK
#include <sys/socket.h>             // for setsockopt, bind, recvfrom, sendto
#include <sysexits.h>               // for EX_CONFIG

#include "error.hh"                 // for error:name, error::description
#include "exception.h"              // for MSG_NetworkError, NetworkError
#include "io.hh"                    // for close, ignored_errno
#include "length.h"                 // for serialise_string, unserialise_string
#include "log.h"                    // for L_ERR, L_OBJ, L_CRIT, L_CONN, L_UDP_WIRE
#include "manager.h"                // for XapiandManager, sig_exit, Xapiand...
#include "opts.h"                   // for opts

UDP::UDP(int port, const char* description, uint8_t major_version, uint8_t minor_version, int flags)
	: port(port),
	  sock(-1),
	  closed(true),
	  flags(flags),
	  description(description),
	  major_version(major_version),
	  minor_version(minor_version)
{}

UDP::~UDP()
{
	if (sock != -1) {
		io::close(sock);
	}
}

bool
UDP::close(bool close) {
	bool was_closed = closed.exchange(true);
	if (!was_closed && sock != -1) {
		if (close) {
			// Dangerously close socket!
			// (make sure no threads are using the file descriptor)
			io::close(sock);
			sock = -1;
		} else {
			io::shutdown(sock, SHUT_RDWR);
		}
	}
	return was_closed;
}

void
UDP::bind(int tries, const std::string& group)
{
	if (!closed.exchange(false)) {
		return;
	}

	int optval = 1;
	unsigned char ttl = 3;
	struct ip_mreq mreq;

	if ((sock = io::socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
		L_CRIT("ERROR: %s socket: %s (%d): %s", description, error::name(errno), errno, error::description(errno));
		sig_exit(-EX_CONFIG);
	}

	if (io::setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) {
		L_ERR("ERROR: %s setsockopt SO_REUSEADDR (sock=%d): %s (%d): %s", description, sock, error::name(errno), errno, error::description(errno));
	}

	if ((flags & UDP_SO_REUSEPORT) != 0) {
#ifdef SO_REUSEPORT_LB
		if (io::setsockopt(sock, SOL_SOCKET, SO_REUSEPORT_LB, &optval, sizeof(optval)) == -1) {
			L_ERR("ERROR: %s setsockopt SO_REUSEPORT_LB (sock=%d): %s (%d): %s", description, sock, error::name(errno), errno, error::description(errno));
		}
#else
		if (io::setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)) == -1) {
			L_ERR("ERROR: %s setsockopt SO_REUSEPORT (sock=%d): %s (%d): %s", description, sock, error::name(errno), errno, error::description(errno));
		}
#endif
	}

	if (io::setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, &optval, sizeof(optval)) == -1) {
		L_ERR("ERROR: %s setsockopt IP_MULTICAST_LOOP (sock=%d): %s (%d): %s", description, sock, error::name(errno), errno, error::description(errno));
	}

	if (io::setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) == -1) {
		L_ERR("ERROR: %s setsockopt IP_MULTICAST_TTL (sock=%d): %s (%d): %s", description, sock, error::name(errno), errno, error::description(errno));
	}

	// use io::setsockopt() to request that the kernel join a multicast group
	memset(&mreq, 0, sizeof(mreq));
	mreq.imr_multiaddr.s_addr = inet_addr(group.c_str());
	mreq.imr_interface.s_addr = htonl(INADDR_ANY);
	if (io::setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) {
		L_CRIT("ERROR: %s setsockopt IP_ADD_MEMBERSHIP (sock=%d): %s (%d): %s", description, sock, error::name(errno), errno, error::description(errno));
		close();
		sig_exit(-EX_CONFIG);
	}

	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = htonl(INADDR_ANY);  // bind to all addresses (differs from sender)

	for (int i = 0; i < tries; ++i, ++port) {
		addr.sin_port = htons(port);

		if (io::bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
			if (!io::ignored_errno(errno, true, true, true)) {
				if (i == tries - 1) { break; }
				L_CONN("ERROR: %s bind error (sock=%d): %s (%d): %s", description, sock, error::name(errno), errno, error::description(errno));
				continue;
			}
		}

		if (io::fcntl(sock, F_SETFL, io::fcntl(sock, F_GETFL, 0) | O_NONBLOCK) == -1) {
			L_CRIT("ERROR: fcntl O_NONBLOCK (sock=%d): %s (%d): %s", sock, error::name(errno), errno, error::description(errno));
			sig_exit(-EX_CONFIG);
		}

		addr.sin_addr.s_addr = inet_addr(group.c_str());  // setup s_addr for sender (send to group)

		// Flush socket
		L_DELAYED_N(1s, "UDP flush is taking too long...");
		while (true) {
			char buf[1024];
			ssize_t received = io::recv(sock, buf, sizeof(buf), 0);
			if (received < 0 && !io::ignored_errno(errno, false, true, true)) {
				break;
			}
		}
		L_DELAYED_N_CLEAR();

		return;
	}

	L_CRIT("ERROR: %s bind error (sock=%d): %s (%d): %s", description, sock, error::name(errno), errno, error::description(errno));
	close();
	sig_exit(-EX_CONFIG);
}

ssize_t
UDP::send_message(const std::string& message)
{
	if (!closed) {
		L_UDP_WIRE("(sock=%d) <<-- %s", sock, repr(message));

#ifdef MSG_NOSIGNAL
		ssize_t written = io::sendto(sock, message.c_str(), message.size(), MSG_NOSIGNAL, (struct sockaddr *)&addr, sizeof(addr));
#else
		ssize_t written = io::sendto(sock, message.c_str(), message.size(), 0, (struct sockaddr *)&addr, sizeof(addr));
#endif

		if (written < 0) {
			L_ERR("ERROR: sendto error (sock=%d): %s (%d): %s", sock, error::name(errno), errno, error::description(errno));
		}
		return written;
	}
	return 0;
}

ssize_t
UDP::send_message(char type, const std::string& content)
{
	if (!content.empty()) {
		std::string message;
		message.push_back(major_version);
		message.push_back(minor_version);
		message.push_back(type);
		message.append(serialise_string(opts.cluster_name));
		message.append(content);
		return send_message(message);
	}
	return 0;
}

char
UDP::get_message(std::string& result, char max_type)
{
	char buf[1024];
	ssize_t received = io::recv(sock, buf, sizeof(buf), 0);
	if (received < 0) {
		if (!io::ignored_errno(errno, true, true, true)) {
			L_ERR("ERROR: read error (sock=%d): %s (%d): %s", sock, error::name(errno), errno, error::description(errno));
			THROW(NetworkError, error::description(errno));
		}
		L_CONN("Received EOF (sock=%d)!", sock);
		return '\xff';
	} else if (received == 0) {
		// If no messages are available to be received and the peer has performed an orderly shutdown.
		L_CONN("Received EOF (sock=%d)!", sock);
		return '\xff';
	} else if (received < 4) {
		L_CONN("Badly formed message: Incomplete!");
	}

	L_UDP_WIRE("(sock=%d) -->> %s", sock, repr(buf, received));

	const char *p = buf;
	const char *p_end = p + received;

	uint8_t received_major_version = *p++;
	uint8_t received_minor_version = *p++;
	if (received_major_version > major_version || (received_major_version == major_version && received_minor_version > minor_version)) {
		L_CONN("Badly formed message: Protocol version mismatch!");
		return '\xff';
	}

	char type = *p++;
	if (type >= max_type) {
		L_CONN("Badly formed message: Invalid message type %u", unsigned(type));
		return '\xff';
	}

	auto remote_cluster_name = unserialise_string(&p, p_end);
	if (remote_cluster_name.empty()) {
		L_CONN("Badly formed message: No cluster name!");
		return '\xff';
	}

	if (remote_cluster_name != opts.cluster_name) {
		return '\xff';
	}

	result = std::string(p, p_end - p);
	return type;
}
<commit_msg>UDP: Ignore certain UDP errors<commit_after>/*
 * Copyright (C) 2015-2018 Dubalu LLC. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "udp.h"

#include <arpa/inet.h>              // for inet_addr, htonl, htons
#include <cstring>                  // for memset
#include <errno.h>                  // for errno
#include <utility>
#include <fcntl.h>                  // for fcntl, F_GETFL, F_SETFL, O_NONBLOCK
#include <sys/socket.h>             // for setsockopt, bind, recvfrom, sendto
#include <sysexits.h>               // for EX_CONFIG

#include "error.hh"                 // for error:name, error::description
#include "exception.h"              // for MSG_NetworkError, NetworkError
#include "io.hh"                    // for close, ignored_errno
#include "length.h"                 // for serialise_string, unserialise_string
#include "log.h"                    // for L_ERR, L_OBJ, L_CRIT, L_CONN, L_UDP_WIRE
#include "manager.h"                // for XapiandManager, sig_exit, Xapiand...
#include "opts.h"                   // for opts

UDP::UDP(int port, const char* description, uint8_t major_version, uint8_t minor_version, int flags)
	: port(port),
	  sock(-1),
	  closed(true),
	  flags(flags),
	  description(description),
	  major_version(major_version),
	  minor_version(minor_version)
{}

UDP::~UDP()
{
	if (sock != -1) {
		io::close(sock);
	}
}

bool
UDP::close(bool close) {
	bool was_closed = closed.exchange(true);
	if (!was_closed && sock != -1) {
		if (close) {
			// Dangerously close socket!
			// (make sure no threads are using the file descriptor)
			io::close(sock);
			sock = -1;
		} else {
			io::shutdown(sock, SHUT_RDWR);
		}
	}
	return was_closed;
}

void
UDP::bind(int tries, const std::string& group)
{
	if (!closed.exchange(false)) {
		return;
	}

	int optval = 1;
	unsigned char ttl = 3;
	struct ip_mreq mreq;

	if ((sock = io::socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
		L_CRIT("ERROR: %s socket: %s (%d): %s", description, error::name(errno), errno, error::description(errno));
		sig_exit(-EX_CONFIG);
	}

	if (io::setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) {
		L_ERR("ERROR: %s setsockopt SO_REUSEADDR (sock=%d): %s (%d): %s", description, sock, error::name(errno), errno, error::description(errno));
	}

	if ((flags & UDP_SO_REUSEPORT) != 0) {
#ifdef SO_REUSEPORT_LB
		if (io::setsockopt(sock, SOL_SOCKET, SO_REUSEPORT_LB, &optval, sizeof(optval)) == -1) {
			L_ERR("ERROR: %s setsockopt SO_REUSEPORT_LB (sock=%d): %s (%d): %s", description, sock, error::name(errno), errno, error::description(errno));
		}
#else
		if (io::setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)) == -1) {
			L_ERR("ERROR: %s setsockopt SO_REUSEPORT (sock=%d): %s (%d): %s", description, sock, error::name(errno), errno, error::description(errno));
		}
#endif
	}

	if (io::setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, &optval, sizeof(optval)) == -1) {
		L_ERR("ERROR: %s setsockopt IP_MULTICAST_LOOP (sock=%d): %s (%d): %s", description, sock, error::name(errno), errno, error::description(errno));
	}

	if (io::setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) == -1) {
		L_ERR("ERROR: %s setsockopt IP_MULTICAST_TTL (sock=%d): %s (%d): %s", description, sock, error::name(errno), errno, error::description(errno));
	}

	// use io::setsockopt() to request that the kernel join a multicast group
	memset(&mreq, 0, sizeof(mreq));
	mreq.imr_multiaddr.s_addr = inet_addr(group.c_str());
	mreq.imr_interface.s_addr = htonl(INADDR_ANY);
	if (io::setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) {
		L_CRIT("ERROR: %s setsockopt IP_ADD_MEMBERSHIP (sock=%d): %s (%d): %s", description, sock, error::name(errno), errno, error::description(errno));
		close();
		sig_exit(-EX_CONFIG);
	}

	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = htonl(INADDR_ANY);  // bind to all addresses (differs from sender)

	for (int i = 0; i < tries; ++i, ++port) {
		addr.sin_port = htons(port);

		if (io::bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
			if (!io::ignored_errno(errno, true, true, true)) {
				if (i == tries - 1) { break; }
				L_CONN("ERROR: %s bind error (sock=%d): %s (%d): %s", description, sock, error::name(errno), errno, error::description(errno));
				continue;
			}
		}

		if (io::fcntl(sock, F_SETFL, io::fcntl(sock, F_GETFL, 0) | O_NONBLOCK) == -1) {
			L_CRIT("ERROR: fcntl O_NONBLOCK (sock=%d): %s (%d): %s", sock, error::name(errno), errno, error::description(errno));
			sig_exit(-EX_CONFIG);
		}

		addr.sin_addr.s_addr = inet_addr(group.c_str());  // setup s_addr for sender (send to group)

		// Flush socket
		L_DELAYED_N(1s, "UDP flush is taking too long...");
		while (true) {
			char buf[1024];
			ssize_t received = io::recv(sock, buf, sizeof(buf), 0);
			if (received < 0 && !io::ignored_errno(errno, false, true, true)) {
				break;
			}
		}
		L_DELAYED_N_CLEAR();

		return;
	}

	L_CRIT("ERROR: %s bind error (sock=%d): %s (%d): %s", description, sock, error::name(errno), errno, error::description(errno));
	close();
	sig_exit(-EX_CONFIG);
}

ssize_t
UDP::send_message(const std::string& message)
{
	if (!closed) {
		L_UDP_WIRE("(sock=%d) <<-- %s", sock, repr(message));

#ifdef MSG_NOSIGNAL
		ssize_t written = io::sendto(sock, message.c_str(), message.size(), MSG_NOSIGNAL, (struct sockaddr *)&addr, sizeof(addr));
#else
		ssize_t written = io::sendto(sock, message.c_str(), message.size(), 0, (struct sockaddr *)&addr, sizeof(addr));
#endif

		if (written < 0) {
			if (!io::ignored_errno(errno, true, true, true)) {
				L_ERR("ERROR: sendto error (sock=%d): %s (%d): %s", sock, error::name(errno), errno, error::description(errno));
			}
		}
		return written;
	}
	return 0;
}

ssize_t
UDP::send_message(char type, const std::string& content)
{
	if (!content.empty()) {
		std::string message;
		message.push_back(major_version);
		message.push_back(minor_version);
		message.push_back(type);
		message.append(serialise_string(opts.cluster_name));
		message.append(content);
		return send_message(message);
	}
	return 0;
}

char
UDP::get_message(std::string& result, char max_type)
{
	char buf[1024];
	ssize_t received = io::recv(sock, buf, sizeof(buf), 0);
	if (received < 0) {
		if (!io::ignored_errno(errno, true, true, true)) {
			L_ERR("ERROR: read error (sock=%d): %s (%d): %s", sock, error::name(errno), errno, error::description(errno));
			THROW(NetworkError, error::description(errno));
		}
		L_CONN("Received EOF (sock=%d)!", sock);
		return '\xff';
	} else if (received == 0) {
		// If no messages are available to be received and the peer has performed an orderly shutdown.
		L_CONN("Received EOF (sock=%d)!", sock);
		return '\xff';
	} else if (received < 4) {
		L_CONN("Badly formed message: Incomplete!");
	}

	L_UDP_WIRE("(sock=%d) -->> %s", sock, repr(buf, received));

	const char *p = buf;
	const char *p_end = p + received;

	uint8_t received_major_version = *p++;
	uint8_t received_minor_version = *p++;
	if (received_major_version > major_version || (received_major_version == major_version && received_minor_version > minor_version)) {
		L_CONN("Badly formed message: Protocol version mismatch!");
		return '\xff';
	}

	char type = *p++;
	if (type >= max_type) {
		L_CONN("Badly formed message: Invalid message type %u", unsigned(type));
		return '\xff';
	}

	auto remote_cluster_name = unserialise_string(&p, p_end);
	if (remote_cluster_name.empty()) {
		L_CONN("Badly formed message: No cluster name!");
		return '\xff';
	}

	if (remote_cluster_name != opts.cluster_name) {
		return '\xff';
	}

	result = std::string(p, p_end - p);
	return type;
}
<|endoftext|>


<commit_before>#include <QtTest/QtTest>

#include "../OpenGestureControl/bluetoothdevicelistmodel.h"

class TestBluetoothDeviceListModel : public QObject
{
    Q_OBJECT
private slots:
    void storingAndRetrievingBluetoothDevice();
};

void TestBluetoothDeviceListModel::storingAndRetrievingBluetoothDevice()
{
    // Arrange
    QString name = "Example device";
    QString deviceId = "00000000-0000-1000-8000-00805F9B34FB";

    BluetoothDeviceListModel *bluetoothDeviceListModel = new BluetoothDeviceListModel();
    BluetoothDevice *bluetoothDevice = new BluetoothDevice(name, deviceId);

    // Act
    bluetoothDeviceListModel->addDevice(bluetoothDevice);
    BluetoothDevice *retrievedBluetoothDevice = bluetoothDeviceListModel->get(0);

    // Assert
    QVERIFY(retrievedBluetoothDevice->name() == name);
    QVERIFY(retrievedBluetoothDevice->deviceId() == deviceId);
}

QTEST_MAIN(TestBluetoothDeviceListModel)
#include "testbluetoothdevicelistmodel.moc"
<commit_msg>added BT tests to test rest of BluetoothDeviceListModel<commit_after>#include <QtTest/QtTest>

#include "../OpenGestureControl/bluetoothdevicelistmodel.h"

class TestBluetoothDeviceListModel : public QObject
{
    Q_OBJECT
private slots:
    void storingAndRetrievingBluetoothDevice();
    void getCorrectBluetoothDeviceCount();
    void correctlyClearBluetoothDeviceCount();
};

void TestBluetoothDeviceListModel::storingAndRetrievingBluetoothDevice()
{
    // Arrange
    QString name = "Example device";
    QString deviceId = "00000000-0000-1000-8000-00805F9B34FB";

    BluetoothDeviceListModel *bluetoothDeviceListModel = new BluetoothDeviceListModel();
    BluetoothDevice *bluetoothDevice = new BluetoothDevice(name, deviceId);

    // Act
    bluetoothDeviceListModel->addDevice(bluetoothDevice);
    BluetoothDevice *retrievedBluetoothDevice = bluetoothDeviceListModel->get(0);

    // Assert
    QVERIFY(retrievedBluetoothDevice->name() == name);
    QVERIFY(retrievedBluetoothDevice->deviceId() == deviceId);
}

void TestBluetoothDeviceListModel::getCorrectBluetoothDeviceCount()
{
    // Arrange
    QString name1 = "Example device 1";
    QString name2 = "Example device 2";
    QString name3 = "Example device 3";
    QString deviceId1 = "00000000-0000-1000-8000-00805F9B34FA";
    QString deviceId2 = "00000000-0000-1000-8000-00805F9B34FB";
    QString deviceId3 = "00000000-0000-1000-8000-00805F9B34FC";

    BluetoothDeviceListModel *bluetoothDeviceListModel = new BluetoothDeviceListModel();
    BluetoothDevice *bluetoothDevice1 = new BluetoothDevice(name1, deviceId1);
    BluetoothDevice *bluetoothDevice2 = new BluetoothDevice(name2, deviceId2);
    BluetoothDevice *bluetoothDevice3 = new BluetoothDevice(name3, deviceId3);

    bluetoothDeviceListModel->addDevice(bluetoothDevice1);
    bluetoothDeviceListModel->addDevice(bluetoothDevice2);
    bluetoothDeviceListModel->addDevice(bluetoothDevice3);

    // Act
    int deviceCount = bluetoothDeviceListModel->rowCount();

    // Assert
    QVERIFY(deviceCount == 3);
}

void TestBluetoothDeviceListModel::correctlyClearBluetoothDeviceCount()
{
    // Arrange
    QString name1 = "Example device 1";
    QString name2 = "Example device 2";
    QString name3 = "Example device 3";
    QString deviceId1 = "00000000-0000-1000-8000-00805F9B34FA";
    QString deviceId2 = "00000000-0000-1000-8000-00805F9B34FB";
    QString deviceId3 = "00000000-0000-1000-8000-00805F9B34FC";

    BluetoothDeviceListModel *bluetoothDeviceListModel = new BluetoothDeviceListModel();
    BluetoothDevice *bluetoothDevice1 = new BluetoothDevice(name1, deviceId1);
    BluetoothDevice *bluetoothDevice2 = new BluetoothDevice(name2, deviceId2);
    BluetoothDevice *bluetoothDevice3 = new BluetoothDevice(name3, deviceId3);

    bluetoothDeviceListModel->addDevice(bluetoothDevice1);
    bluetoothDeviceListModel->addDevice(bluetoothDevice2);
    bluetoothDeviceListModel->addDevice(bluetoothDevice3);

    // Act
    bluetoothDeviceListModel->clear();

    // Assert
    QVERIFY(bluetoothDeviceListModel->rowCount() == 0);
}

QTEST_MAIN(TestBluetoothDeviceListModel)
#include "testbluetoothdevicelistmodel.moc"
<|endoftext|>