<commit_before>// Copyright (c) 2019-2020 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <evo/mnauth.h>

#include <evo/deterministicmns.h>
#include <llmq/quorums_utils.h>
#include <masternode/activemasternode.h>
#include <masternode/masternode-meta.h>
#include <masternode/masternode-sync.h>
#include <net.h>
#include <net_processing.h>
#include <netmessagemaker.h>
#include <validation.h>

#include <unordered_set>

void CMNAuth::PushMNAUTH(CNode* pnode, CConnman& connman)
{
    if (!fMasternodeMode || activeMasternodeInfo.proTxHash.IsNull()) {
        return;
    }

    uint256 signHash;
    {
        LOCK(pnode->cs_mnauth);
        if (pnode->receivedMNAuthChallenge.IsNull()) {
            return;
        }
        // We include fInbound in signHash to forbid interchanging of challenges by a man in the middle (MITM). This way
        // we protect ourselves against MITM in this form:
        //   node1 <- Eve -> node2
        // It does not protect against:
        //   node1 -> Eve -> node2
        // This is ok as we only use MNAUTH as a DoS protection and not for sensitive stuff
        signHash = ::SerializeHash(std::make_tuple(*activeMasternodeInfo.blsPubKeyOperator, pnode->receivedMNAuthChallenge, pnode->fInbound));
    }

    CMNAuth mnauth;
    mnauth.proRegTxHash = activeMasternodeInfo.proTxHash;
    mnauth.sig = activeMasternodeInfo.blsKeyOperator->Sign(signHash);

    LogPrint(BCLog::NET, "CMNAuth::%s -- Sending MNAUTH, peer=%d\n", __func__, pnode->GetId());

    connman.PushMessage(pnode, CNetMsgMaker(pnode->GetSendVersion()).Make(NetMsgType::MNAUTH, mnauth));
}

void CMNAuth::ProcessMessage(CNode* pnode, const std::string& strCommand, CDataStream& vRecv, CConnman& connman)
{
    if (!masternodeSync.IsBlockchainSynced()) {
        // we can't verify MNAUTH messages when we don't have the latest MN list
        return;
    }

    if (strCommand == NetMsgType::MNAUTH) {
        CMNAuth mnauth;
        vRecv >> mnauth;

        // only one MNAUTH allowed
        bool fAlreadyHaveMNAUTH = false;
        {
            LOCK(pnode->cs_mnauth);
            fAlreadyHaveMNAUTH = !pnode->verifiedProRegTxHash.IsNull();
        }
        if (fAlreadyHaveMNAUTH) {
            LOCK(cs_main);
            Misbehaving(pnode->GetId(), 100, "duplicate mnauth");
            return;
        }

        if ((~pnode->nServices) & NODE_NETWORK)) {
            // NODE_NETWORK bit is missing in node's services
            LOCK(cs_main);
            Misbehaving(pnode->GetId(), 100, "mnauth from a node with invalid services");
            return;
        }

        if (mnauth.proRegTxHash.IsNull()) {
            LOCK(cs_main);
            Misbehaving(pnode->GetId(), 100, "empty mnauth proRegTxHash");
            return;
        }

        if (!mnauth.sig.IsValid()) {
            LOCK(cs_main);
            Misbehaving(pnode->GetId(), 100, "invalid mnauth signature");
            return;
        }

        auto mnList = deterministicMNManager->GetListAtChainTip();
        auto dmn = mnList.GetMN(mnauth.proRegTxHash);
        if (!dmn) {
            LOCK(cs_main);
            // in case node was unlucky and not up to date, just let it be connected as a regular node, which gives it
            // a chance to get up-to-date and thus realize that it's not a MN anymore. We still give it a
            // low DoS score.
            Misbehaving(pnode->GetId(), 10, "missing mnauth masternode");
            return;
        }

        uint256 signHash;
        {
            LOCK(pnode->cs_mnauth);
            // See comment in PushMNAUTH (fInbound is negated here as we're on the other side of the connection)
            signHash = ::SerializeHash(std::make_tuple(dmn->pdmnState->pubKeyOperator, pnode->sentMNAuthChallenge, !pnode->fInbound));
        }

        if (!mnauth.sig.VerifyInsecure(dmn->pdmnState->pubKeyOperator.Get(), signHash)) {
            LOCK(cs_main);
            // Same as above, MN seems to not know its fate yet, so give it a chance to update. If this is a
            // malicious node (DoSing us), it'll get banned soon.
            Misbehaving(pnode->GetId(), 10, "mnauth signature verification failed");
            return;
        }

        if (!pnode->fInbound) {
            mmetaman.GetMetaInfo(mnauth.proRegTxHash)->SetLastOutboundSuccess(GetAdjustedTime());
            if (pnode->fMasternodeProbe) {
                LogPrint(BCLog::NET, "CMNAuth::ProcessMessage -- Masternode probe successful for %s, disconnecting. peer=%d\n",
                         mnauth.proRegTxHash.ToString(), pnode->GetId());
                pnode->fDisconnect = true;
                return;
            }
        }

        connman.ForEachNode([&](CNode* pnode2) {
            if (pnode->fDisconnect) {
                // we've already disconnected the new peer
                return;
            }

            if (pnode2->verifiedProRegTxHash == mnauth.proRegTxHash) {
                if (fMasternodeMode) {
                    auto deterministicOutbound = llmq::CLLMQUtils::DeterministicOutboundConnection(activeMasternodeInfo.proTxHash, mnauth.proRegTxHash);
                    LogPrint(BCLog::NET, "CMNAuth::ProcessMessage -- Masternode %s has already verified as peer %d, deterministicOutbound=%s. peer=%d\n",
                             mnauth.proRegTxHash.ToString(), pnode2->GetId(), deterministicOutbound.ToString(), pnode->GetId());
                    if (deterministicOutbound == activeMasternodeInfo.proTxHash) {
                        if (pnode2->fInbound) {
                            LogPrint(BCLog::NET, "CMNAuth::ProcessMessage -- dropping old inbound, peer=%d\n", pnode2->GetId());
                            pnode2->fDisconnect = true;
                        } else if (pnode->fInbound) {
                            LogPrint(BCLog::NET, "CMNAuth::ProcessMessage -- dropping new inbound, peer=%d\n", pnode->GetId());
                            pnode->fDisconnect = true;
                        }
                    } else {
                        if (!pnode2->fInbound) {
                            LogPrint(BCLog::NET, "CMNAuth::ProcessMessage -- dropping old outbound, peer=%d\n", pnode2->GetId());
                            pnode2->fDisconnect = true;
                        } else if (!pnode->fInbound) {
                            LogPrint(BCLog::NET, "CMNAuth::ProcessMessage -- dropping new outbound, peer=%d\n", pnode->GetId());
                            pnode->fDisconnect = true;
                        }
                    }
                } else {
                    LogPrint(BCLog::NET, "CMNAuth::ProcessMessage -- Masternode %s has already verified as peer %d, dropping new connection. peer=%d\n",
                            mnauth.proRegTxHash.ToString(), pnode2->GetId(), pnode->GetId());
                    pnode->fDisconnect = true;
                }
            }
        });

        if (pnode->fDisconnect) {
            return;
        }

        {
            LOCK(pnode->cs_mnauth);
            pnode->verifiedProRegTxHash = mnauth.proRegTxHash;
            pnode->verifiedPubKeyHash = dmn->pdmnState->pubKeyOperator.GetHash();
        }

        LogPrint(BCLog::NET, "CMNAuth::%s -- Valid MNAUTH for %s, peer=%d\n", __func__, mnauth.proRegTxHash.ToString(), pnode->GetId());
    }
}

void CMNAuth::NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff, CConnman& connman)
{
    // we're only interested in updated/removed MNs. Added MNs are of no interest for us
    if (diff.updatedMNs.empty() && diff.removedMns.empty()) {
        return;
    }

    connman.ForEachNode([&](CNode* pnode) {
        LOCK(pnode->cs_mnauth);
        if (pnode->verifiedProRegTxHash.IsNull()) {
            return;
        }
        auto verifiedDmn = oldMNList.GetMN(pnode->verifiedProRegTxHash);
        if (!verifiedDmn) {
            return;
        }
        bool doRemove = false;
        if (diff.removedMns.count(verifiedDmn->GetInternalId())) {
            doRemove = true;
        } else {
            auto it = diff.updatedMNs.find(verifiedDmn->GetInternalId());
            if (it != diff.updatedMNs.end()) {
                if ((it->second.fields & CDeterministicMNStateDiff::Field_pubKeyOperator) && it->second.state.pubKeyOperator.GetHash() != pnode->verifiedPubKeyHash) {
                    doRemove = true;
                }
            }
        }

        if (doRemove) {
            LogPrint(BCLog::NET, "CMNAuth::NotifyMasternodeListChanged -- Disconnecting MN %s due to key changed/removed, peer=%d\n",
                     pnode->verifiedProRegTxHash.ToString(), pnode->GetId());
            pnode->fDisconnect = true;
        }
    });
}
<commit_msg>compile<commit_after>// Copyright (c) 2019-2020 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <evo/mnauth.h>

#include <evo/deterministicmns.h>
#include <llmq/quorums_utils.h>
#include <masternode/activemasternode.h>
#include <masternode/masternode-meta.h>
#include <masternode/masternode-sync.h>
#include <net.h>
#include <net_processing.h>
#include <netmessagemaker.h>
#include <validation.h>

#include <unordered_set>

void CMNAuth::PushMNAUTH(CNode* pnode, CConnman& connman)
{
    if (!fMasternodeMode || activeMasternodeInfo.proTxHash.IsNull()) {
        return;
    }

    uint256 signHash;
    {
        LOCK(pnode->cs_mnauth);
        if (pnode->receivedMNAuthChallenge.IsNull()) {
            return;
        }
        // We include fInbound in signHash to forbid interchanging of challenges by a man in the middle (MITM). This way
        // we protect ourselves against MITM in this form:
        //   node1 <- Eve -> node2
        // It does not protect against:
        //   node1 -> Eve -> node2
        // This is ok as we only use MNAUTH as a DoS protection and not for sensitive stuff
        signHash = ::SerializeHash(std::make_tuple(*activeMasternodeInfo.blsPubKeyOperator, pnode->receivedMNAuthChallenge, pnode->fInbound));
    }

    CMNAuth mnauth;
    mnauth.proRegTxHash = activeMasternodeInfo.proTxHash;
    mnauth.sig = activeMasternodeInfo.blsKeyOperator->Sign(signHash);

    LogPrint(BCLog::NET, "CMNAuth::%s -- Sending MNAUTH, peer=%d\n", __func__, pnode->GetId());

    connman.PushMessage(pnode, CNetMsgMaker(pnode->GetSendVersion()).Make(NetMsgType::MNAUTH, mnauth));
}

void CMNAuth::ProcessMessage(CNode* pnode, const std::string& strCommand, CDataStream& vRecv, CConnman& connman)
{
    if (!masternodeSync.IsBlockchainSynced()) {
        // we can't verify MNAUTH messages when we don't have the latest MN list
        return;
    }

    if (strCommand == NetMsgType::MNAUTH) {
        CMNAuth mnauth;
        vRecv >> mnauth;

        // only one MNAUTH allowed
        bool fAlreadyHaveMNAUTH = false;
        {
            LOCK(pnode->cs_mnauth);
            fAlreadyHaveMNAUTH = !pnode->verifiedProRegTxHash.IsNull();
        }
        if (fAlreadyHaveMNAUTH) {
            LOCK(cs_main);
            Misbehaving(pnode->GetId(), 100, "duplicate mnauth");
            return;
        }

        if ((~pnode->nServices) & NODE_NETWORK) {
            // NODE_NETWORK bit is missing in node's services
            LOCK(cs_main);
            Misbehaving(pnode->GetId(), 100, "mnauth from a node with invalid services");
            return;
        }

        if (mnauth.proRegTxHash.IsNull()) {
            LOCK(cs_main);
            Misbehaving(pnode->GetId(), 100, "empty mnauth proRegTxHash");
            return;
        }

        if (!mnauth.sig.IsValid()) {
            LOCK(cs_main);
            Misbehaving(pnode->GetId(), 100, "invalid mnauth signature");
            return;
        }

        auto mnList = deterministicMNManager->GetListAtChainTip();
        auto dmn = mnList.GetMN(mnauth.proRegTxHash);
        if (!dmn) {
            LOCK(cs_main);
            // in case node was unlucky and not up to date, just let it be connected as a regular node, which gives it
            // a chance to get up-to-date and thus realize that it's not a MN anymore. We still give it a
            // low DoS score.
            Misbehaving(pnode->GetId(), 10, "missing mnauth masternode");
            return;
        }

        uint256 signHash;
        {
            LOCK(pnode->cs_mnauth);
            // See comment in PushMNAUTH (fInbound is negated here as we're on the other side of the connection)
            signHash = ::SerializeHash(std::make_tuple(dmn->pdmnState->pubKeyOperator, pnode->sentMNAuthChallenge, !pnode->fInbound));
        }

        if (!mnauth.sig.VerifyInsecure(dmn->pdmnState->pubKeyOperator.Get(), signHash)) {
            LOCK(cs_main);
            // Same as above, MN seems to not know its fate yet, so give it a chance to update. If this is a
            // malicious node (DoSing us), it'll get banned soon.
            Misbehaving(pnode->GetId(), 10, "mnauth signature verification failed");
            return;
        }

        if (!pnode->fInbound) {
            mmetaman.GetMetaInfo(mnauth.proRegTxHash)->SetLastOutboundSuccess(GetAdjustedTime());
            if (pnode->fMasternodeProbe) {
                LogPrint(BCLog::NET, "CMNAuth::ProcessMessage -- Masternode probe successful for %s, disconnecting. peer=%d\n",
                         mnauth.proRegTxHash.ToString(), pnode->GetId());
                pnode->fDisconnect = true;
                return;
            }
        }

        connman.ForEachNode([&](CNode* pnode2) {
            if (pnode->fDisconnect) {
                // we've already disconnected the new peer
                return;
            }

            if (pnode2->verifiedProRegTxHash == mnauth.proRegTxHash) {
                if (fMasternodeMode) {
                    auto deterministicOutbound = llmq::CLLMQUtils::DeterministicOutboundConnection(activeMasternodeInfo.proTxHash, mnauth.proRegTxHash);
                    LogPrint(BCLog::NET, "CMNAuth::ProcessMessage -- Masternode %s has already verified as peer %d, deterministicOutbound=%s. peer=%d\n",
                             mnauth.proRegTxHash.ToString(), pnode2->GetId(), deterministicOutbound.ToString(), pnode->GetId());
                    if (deterministicOutbound == activeMasternodeInfo.proTxHash) {
                        if (pnode2->fInbound) {
                            LogPrint(BCLog::NET, "CMNAuth::ProcessMessage -- dropping old inbound, peer=%d\n", pnode2->GetId());
                            pnode2->fDisconnect = true;
                        } else if (pnode->fInbound) {
                            LogPrint(BCLog::NET, "CMNAuth::ProcessMessage -- dropping new inbound, peer=%d\n", pnode->GetId());
                            pnode->fDisconnect = true;
                        }
                    } else {
                        if (!pnode2->fInbound) {
                            LogPrint(BCLog::NET, "CMNAuth::ProcessMessage -- dropping old outbound, peer=%d\n", pnode2->GetId());
                            pnode2->fDisconnect = true;
                        } else if (!pnode->fInbound) {
                            LogPrint(BCLog::NET, "CMNAuth::ProcessMessage -- dropping new outbound, peer=%d\n", pnode->GetId());
                            pnode->fDisconnect = true;
                        }
                    }
                } else {
                    LogPrint(BCLog::NET, "CMNAuth::ProcessMessage -- Masternode %s has already verified as peer %d, dropping new connection. peer=%d\n",
                            mnauth.proRegTxHash.ToString(), pnode2->GetId(), pnode->GetId());
                    pnode->fDisconnect = true;
                }
            }
        });

        if (pnode->fDisconnect) {
            return;
        }

        {
            LOCK(pnode->cs_mnauth);
            pnode->verifiedProRegTxHash = mnauth.proRegTxHash;
            pnode->verifiedPubKeyHash = dmn->pdmnState->pubKeyOperator.GetHash();
        }

        LogPrint(BCLog::NET, "CMNAuth::%s -- Valid MNAUTH for %s, peer=%d\n", __func__, mnauth.proRegTxHash.ToString(), pnode->GetId());
    }
}

void CMNAuth::NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff, CConnman& connman)
{
    // we're only interested in updated/removed MNs. Added MNs are of no interest for us
    if (diff.updatedMNs.empty() && diff.removedMns.empty()) {
        return;
    }

    connman.ForEachNode([&](CNode* pnode) {
        LOCK(pnode->cs_mnauth);
        if (pnode->verifiedProRegTxHash.IsNull()) {
            return;
        }
        auto verifiedDmn = oldMNList.GetMN(pnode->verifiedProRegTxHash);
        if (!verifiedDmn) {
            return;
        }
        bool doRemove = false;
        if (diff.removedMns.count(verifiedDmn->GetInternalId())) {
            doRemove = true;
        } else {
            auto it = diff.updatedMNs.find(verifiedDmn->GetInternalId());
            if (it != diff.updatedMNs.end()) {
                if ((it->second.fields & CDeterministicMNStateDiff::Field_pubKeyOperator) && it->second.state.pubKeyOperator.GetHash() != pnode->verifiedPubKeyHash) {
                    doRemove = true;
                }
            }
        }

        if (doRemove) {
            LogPrint(BCLog::NET, "CMNAuth::NotifyMasternodeListChanged -- Disconnecting MN %s due to key changed/removed, peer=%d\n",
                     pnode->verifiedProRegTxHash.ToString(), pnode->GetId());
            pnode->fDisconnect = true;
        }
    });
}
<|endoftext|>


<commit_before>// Copyright (c) 2019-2020 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <evo/mnauth.h>

#include <evo/deterministicmns.h>
#include <llmq/quorums_utils.h>
#include <masternode/activemasternode.h>
#include <masternode/masternode-meta.h>
#include <masternode/masternode-sync.h>
#include <net.h>
#include <net_processing.h>
#include <netmessagemaker.h>
#include <validation.h>

#include <unordered_set>

void CMNAuth::PushMNAUTH(CNode* pnode, CConnman& connman)
{
    if (!fMasternodeMode || activeMasternodeInfo.proTxHash.IsNull()) {
        return;
    }

    uint256 signHash;
    {
        LOCK(pnode->cs_mnauth);
        if (pnode->receivedMNAuthChallenge.IsNull()) {
            return;
        }
        // We include fInbound in signHash to forbid interchanging of challenges by a man in the middle (MITM). This way
        // we protect ourselves against MITM in this form:
        //   node1 <- Eve -> node2
        // It does not protect against:
        //   node1 -> Eve -> node2
        // This is ok as we only use MNAUTH as a DoS protection and not for sensitive stuff
        signHash = ::SerializeHash(std::make_tuple(*activeMasternodeInfo.blsPubKeyOperator, pnode->receivedMNAuthChallenge, pnode->fInbound));
    }

    CMNAuth mnauth;
    mnauth.proRegTxHash = activeMasternodeInfo.proTxHash;
    mnauth.sig = activeMasternodeInfo.blsKeyOperator->Sign(signHash);

    LogPrint(BCLog::NET, "CMNAuth::%s -- Sending MNAUTH, peer=%d\n", __func__, pnode->GetId());

    connman.PushMessage(pnode, CNetMsgMaker(pnode->GetSendVersion()).Make(NetMsgType::MNAUTH, mnauth));
}

void CMNAuth::ProcessMessage(CNode* pnode, const std::string& strCommand, CDataStream& vRecv, CConnman& connman)
{
    if (!masternodeSync.IsBlockchainSynced()) {
        // we can't verify MNAUTH messages when we don't have the latest MN list
        return;
    }

    if (strCommand == NetMsgType::MNAUTH) {
        CMNAuth mnauth;
        vRecv >> mnauth;

        // only one MNAUTH allowed
        bool fAlreadyHaveMNAUTH = false;
        {
            LOCK(pnode->cs_mnauth);
            fAlreadyHaveMNAUTH = !pnode->verifiedProRegTxHash.IsNull();
        }
        if (fAlreadyHaveMNAUTH) {
            LOCK(cs_main);
            Misbehaving(pnode->GetId(), 100, "duplicate mnauth");
            return;
        }

        if ((~pnode->nServices) & (NODE_NETWORK | NODE_BLOOM)) {
            // either NODE_NETWORK or NODE_BLOOM bit is missing in node's services
            LOCK(cs_main);
            Misbehaving(pnode->GetId(), 100, "mnauth from a node with invalid services");
            return;
        }

        if (mnauth.proRegTxHash.IsNull()) {
            LOCK(cs_main);
            Misbehaving(pnode->GetId(), 100, "empty mnauth proRegTxHash");
            return;
        }

        if (!mnauth.sig.IsValid()) {
            LOCK(cs_main);
            Misbehaving(pnode->GetId(), 100, "invalid mnauth signature");
            return;
        }

        auto mnList = deterministicMNManager->GetListAtChainTip();
        auto dmn = mnList.GetMN(mnauth.proRegTxHash);
        if (!dmn) {
            LOCK(cs_main);
            // in case node was unlucky and not up to date, just let it be connected as a regular node, which gives it
            // a chance to get up-to-date and thus realize that it's not a MN anymore. We still give it a
            // low DoS score.
            Misbehaving(pnode->GetId(), 10, "missing mnauth masternode");
            return;
        }

        uint256 signHash;
        {
            LOCK(pnode->cs_mnauth);
            // See comment in PushMNAUTH (fInbound is negated here as we're on the other side of the connection)
            signHash = ::SerializeHash(std::make_tuple(dmn->pdmnState->pubKeyOperator, pnode->sentMNAuthChallenge, !pnode->fInbound));
        }

        if (!mnauth.sig.VerifyInsecure(dmn->pdmnState->pubKeyOperator.Get(), signHash)) {
            LOCK(cs_main);
            // Same as above, MN seems to not know its fate yet, so give it a chance to update. If this is a
            // malicious node (DoSing us), it'll get banned soon.
            Misbehaving(pnode->GetId(), 10, "mnauth signature verification failed");
            return;
        }

        if (!pnode->fInbound) {
            mmetaman.GetMetaInfo(mnauth.proRegTxHash)->SetLastOutboundSuccess(GetAdjustedTime());
            if (pnode->fMasternodeProbe) {
                LogPrint(BCLog::NET, "CMNAuth::ProcessMessage -- Masternode probe successful for %s, disconnecting. peer=%d\n",
                         mnauth.proRegTxHash.ToString(), pnode->GetId());
                pnode->fDisconnect = true;
                return;
            }
        }

        connman.ForEachNode([&](CNode* pnode2) {
            if (pnode->fDisconnect) {
                // we've already disconnected the new peer
                return;
            }

            if (pnode2->verifiedProRegTxHash == mnauth.proRegTxHash) {
                if (fMasternodeMode) {
                    auto deterministicOutbound = llmq::CLLMQUtils::DeterministicOutboundConnection(activeMasternodeInfo.proTxHash, mnauth.proRegTxHash);
                    LogPrint(BCLog::NET, "CMNAuth::ProcessMessage -- Masternode %s has already verified as peer %d, deterministicOutbound=%s. peer=%d\n",
                             mnauth.proRegTxHash.ToString(), pnode2->GetId(), deterministicOutbound.ToString(), pnode->GetId());
                    if (deterministicOutbound == activeMasternodeInfo.proTxHash) {
                        if (pnode2->fInbound) {
                            LogPrint(BCLog::NET, "CMNAuth::ProcessMessage -- dropping old inbound, peer=%d\n", pnode2->GetId());
                            pnode2->fDisconnect = true;
                        } else if (pnode->fInbound) {
                            LogPrint(BCLog::NET, "CMNAuth::ProcessMessage -- dropping new inbound, peer=%d\n", pnode->GetId());
                            pnode->fDisconnect = true;
                        }
                    } else {
                        if (!pnode2->fInbound) {
                            LogPrint(BCLog::NET, "CMNAuth::ProcessMessage -- dropping old outbound, peer=%d\n", pnode2->GetId());
                            pnode2->fDisconnect = true;
                        } else if (!pnode->fInbound) {
                            LogPrint(BCLog::NET, "CMNAuth::ProcessMessage -- dropping new outbound, peer=%d\n", pnode->GetId());
                            pnode->fDisconnect = true;
                        }
                    }
                } else {
                    LogPrint(BCLog::NET, "CMNAuth::ProcessMessage -- Masternode %s has already verified as peer %d, dropping new connection. peer=%d\n",
                            mnauth.proRegTxHash.ToString(), pnode2->GetId(), pnode->GetId());
                    pnode->fDisconnect = true;
                }
            }
        });

        if (pnode->fDisconnect) {
            return;
        }

        {
            LOCK(pnode->cs_mnauth);
            pnode->verifiedProRegTxHash = mnauth.proRegTxHash;
            pnode->verifiedPubKeyHash = dmn->pdmnState->pubKeyOperator.GetHash();
        }

        LogPrint(BCLog::NET, "CMNAuth::%s -- Valid MNAUTH for %s, peer=%d\n", __func__, mnauth.proRegTxHash.ToString(), pnode->GetId());
    }
}

void CMNAuth::NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff, CConnman& connman)
{
    // we're only interested in updated/removed MNs. Added MNs are of no interest for us
    if (diff.updatedMNs.empty() && diff.removedMns.empty()) {
        return;
    }

    connman.ForEachNode([&](CNode* pnode) {
        LOCK(pnode->cs_mnauth);
        if (pnode->verifiedProRegTxHash.IsNull()) {
            return;
        }
        auto verifiedDmn = oldMNList.GetMN(pnode->verifiedProRegTxHash);
        if (!verifiedDmn) {
            return;
        }
        bool doRemove = false;
        if (diff.removedMns.count(verifiedDmn->GetInternalId())) {
            doRemove = true;
        } else {
            auto it = diff.updatedMNs.find(verifiedDmn->GetInternalId());
            if (it != diff.updatedMNs.end()) {
                if ((it->second.fields & CDeterministicMNStateDiff::Field_pubKeyOperator) && it->second.state.pubKeyOperator.GetHash() != pnode->verifiedPubKeyHash) {
                    doRemove = true;
                }
            }
        }

        if (doRemove) {
            LogPrint(BCLog::NET, "CMNAuth::NotifyMasternodeListChanged -- Disconnecting MN %s due to key changed/removed, peer=%d\n",
                     pnode->verifiedProRegTxHash.ToString(), pnode->GetId());
            pnode->fDisconnect = true;
        }
    });
}
<commit_msg>remove bloom requirement for mn<commit_after>// Copyright (c) 2019-2020 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <evo/mnauth.h>

#include <evo/deterministicmns.h>
#include <llmq/quorums_utils.h>
#include <masternode/activemasternode.h>
#include <masternode/masternode-meta.h>
#include <masternode/masternode-sync.h>
#include <net.h>
#include <net_processing.h>
#include <netmessagemaker.h>
#include <validation.h>

#include <unordered_set>

void CMNAuth::PushMNAUTH(CNode* pnode, CConnman& connman)
{
    if (!fMasternodeMode || activeMasternodeInfo.proTxHash.IsNull()) {
        return;
    }

    uint256 signHash;
    {
        LOCK(pnode->cs_mnauth);
        if (pnode->receivedMNAuthChallenge.IsNull()) {
            return;
        }
        // We include fInbound in signHash to forbid interchanging of challenges by a man in the middle (MITM). This way
        // we protect ourselves against MITM in this form:
        //   node1 <- Eve -> node2
        // It does not protect against:
        //   node1 -> Eve -> node2
        // This is ok as we only use MNAUTH as a DoS protection and not for sensitive stuff
        signHash = ::SerializeHash(std::make_tuple(*activeMasternodeInfo.blsPubKeyOperator, pnode->receivedMNAuthChallenge, pnode->fInbound));
    }

    CMNAuth mnauth;
    mnauth.proRegTxHash = activeMasternodeInfo.proTxHash;
    mnauth.sig = activeMasternodeInfo.blsKeyOperator->Sign(signHash);

    LogPrint(BCLog::NET, "CMNAuth::%s -- Sending MNAUTH, peer=%d\n", __func__, pnode->GetId());

    connman.PushMessage(pnode, CNetMsgMaker(pnode->GetSendVersion()).Make(NetMsgType::MNAUTH, mnauth));
}

void CMNAuth::ProcessMessage(CNode* pnode, const std::string& strCommand, CDataStream& vRecv, CConnman& connman)
{
    if (!masternodeSync.IsBlockchainSynced()) {
        // we can't verify MNAUTH messages when we don't have the latest MN list
        return;
    }

    if (strCommand == NetMsgType::MNAUTH) {
        CMNAuth mnauth;
        vRecv >> mnauth;

        // only one MNAUTH allowed
        bool fAlreadyHaveMNAUTH = false;
        {
            LOCK(pnode->cs_mnauth);
            fAlreadyHaveMNAUTH = !pnode->verifiedProRegTxHash.IsNull();
        }
        if (fAlreadyHaveMNAUTH) {
            LOCK(cs_main);
            Misbehaving(pnode->GetId(), 100, "duplicate mnauth");
            return;
        }

        if ((~pnode->nServices) & NODE_NETWORK)) {
            // NODE_NETWORK bit is missing in node's services
            LOCK(cs_main);
            Misbehaving(pnode->GetId(), 100, "mnauth from a node with invalid services");
            return;
        }

        if (mnauth.proRegTxHash.IsNull()) {
            LOCK(cs_main);
            Misbehaving(pnode->GetId(), 100, "empty mnauth proRegTxHash");
            return;
        }

        if (!mnauth.sig.IsValid()) {
            LOCK(cs_main);
            Misbehaving(pnode->GetId(), 100, "invalid mnauth signature");
            return;
        }

        auto mnList = deterministicMNManager->GetListAtChainTip();
        auto dmn = mnList.GetMN(mnauth.proRegTxHash);
        if (!dmn) {
            LOCK(cs_main);
            // in case node was unlucky and not up to date, just let it be connected as a regular node, which gives it
            // a chance to get up-to-date and thus realize that it's not a MN anymore. We still give it a
            // low DoS score.
            Misbehaving(pnode->GetId(), 10, "missing mnauth masternode");
            return;
        }

        uint256 signHash;
        {
            LOCK(pnode->cs_mnauth);
            // See comment in PushMNAUTH (fInbound is negated here as we're on the other side of the connection)
            signHash = ::SerializeHash(std::make_tuple(dmn->pdmnState->pubKeyOperator, pnode->sentMNAuthChallenge, !pnode->fInbound));
        }

        if (!mnauth.sig.VerifyInsecure(dmn->pdmnState->pubKeyOperator.Get(), signHash)) {
            LOCK(cs_main);
            // Same as above, MN seems to not know its fate yet, so give it a chance to update. If this is a
            // malicious node (DoSing us), it'll get banned soon.
            Misbehaving(pnode->GetId(), 10, "mnauth signature verification failed");
            return;
        }

        if (!pnode->fInbound) {
            mmetaman.GetMetaInfo(mnauth.proRegTxHash)->SetLastOutboundSuccess(GetAdjustedTime());
            if (pnode->fMasternodeProbe) {
                LogPrint(BCLog::NET, "CMNAuth::ProcessMessage -- Masternode probe successful for %s, disconnecting. peer=%d\n",
                         mnauth.proRegTxHash.ToString(), pnode->GetId());
                pnode->fDisconnect = true;
                return;
            }
        }

        connman.ForEachNode([&](CNode* pnode2) {
            if (pnode->fDisconnect) {
                // we've already disconnected the new peer
                return;
            }

            if (pnode2->verifiedProRegTxHash == mnauth.proRegTxHash) {
                if (fMasternodeMode) {
                    auto deterministicOutbound = llmq::CLLMQUtils::DeterministicOutboundConnection(activeMasternodeInfo.proTxHash, mnauth.proRegTxHash);
                    LogPrint(BCLog::NET, "CMNAuth::ProcessMessage -- Masternode %s has already verified as peer %d, deterministicOutbound=%s. peer=%d\n",
                             mnauth.proRegTxHash.ToString(), pnode2->GetId(), deterministicOutbound.ToString(), pnode->GetId());
                    if (deterministicOutbound == activeMasternodeInfo.proTxHash) {
                        if (pnode2->fInbound) {
                            LogPrint(BCLog::NET, "CMNAuth::ProcessMessage -- dropping old inbound, peer=%d\n", pnode2->GetId());
                            pnode2->fDisconnect = true;
                        } else if (pnode->fInbound) {
                            LogPrint(BCLog::NET, "CMNAuth::ProcessMessage -- dropping new inbound, peer=%d\n", pnode->GetId());
                            pnode->fDisconnect = true;
                        }
                    } else {
                        if (!pnode2->fInbound) {
                            LogPrint(BCLog::NET, "CMNAuth::ProcessMessage -- dropping old outbound, peer=%d\n", pnode2->GetId());
                            pnode2->fDisconnect = true;
                        } else if (!pnode->fInbound) {
                            LogPrint(BCLog::NET, "CMNAuth::ProcessMessage -- dropping new outbound, peer=%d\n", pnode->GetId());
                            pnode->fDisconnect = true;
                        }
                    }
                } else {
                    LogPrint(BCLog::NET, "CMNAuth::ProcessMessage -- Masternode %s has already verified as peer %d, dropping new connection. peer=%d\n",
                            mnauth.proRegTxHash.ToString(), pnode2->GetId(), pnode->GetId());
                    pnode->fDisconnect = true;
                }
            }
        });

        if (pnode->fDisconnect) {
            return;
        }

        {
            LOCK(pnode->cs_mnauth);
            pnode->verifiedProRegTxHash = mnauth.proRegTxHash;
            pnode->verifiedPubKeyHash = dmn->pdmnState->pubKeyOperator.GetHash();
        }

        LogPrint(BCLog::NET, "CMNAuth::%s -- Valid MNAUTH for %s, peer=%d\n", __func__, mnauth.proRegTxHash.ToString(), pnode->GetId());
    }
}

void CMNAuth::NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff, CConnman& connman)
{
    // we're only interested in updated/removed MNs. Added MNs are of no interest for us
    if (diff.updatedMNs.empty() && diff.removedMns.empty()) {
        return;
    }

    connman.ForEachNode([&](CNode* pnode) {
        LOCK(pnode->cs_mnauth);
        if (pnode->verifiedProRegTxHash.IsNull()) {
            return;
        }
        auto verifiedDmn = oldMNList.GetMN(pnode->verifiedProRegTxHash);
        if (!verifiedDmn) {
            return;
        }
        bool doRemove = false;
        if (diff.removedMns.count(verifiedDmn->GetInternalId())) {
            doRemove = true;
        } else {
            auto it = diff.updatedMNs.find(verifiedDmn->GetInternalId());
            if (it != diff.updatedMNs.end()) {
                if ((it->second.fields & CDeterministicMNStateDiff::Field_pubKeyOperator) && it->second.state.pubKeyOperator.GetHash() != pnode->verifiedPubKeyHash) {
                    doRemove = true;
                }
            }
        }

        if (doRemove) {
            LogPrint(BCLog::NET, "CMNAuth::NotifyMasternodeListChanged -- Disconnecting MN %s due to key changed/removed, peer=%d\n",
                     pnode->verifiedProRegTxHash.ToString(), pnode->GetId());
            pnode->fDisconnect = true;
        }
    });
}
<|endoftext|>


<commit_before>/*************************************************************************
 * libjson-rpc-cpp
 *************************************************************************
 * @file    httpserver.cpp
 * @date    31.12.2012
 * @author  Peter Spiess-Knafl <dev@spiessknafl.at>
 * @license See attached LICENSE.txt
 ************************************************************************/

#include "httpserver.h"
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <jsonrpccpp/common/specificationparser.h>
#include <sstream>

using namespace jsonrpc;
using namespace std;

#define BUFFERSIZE 65536

struct mhd_coninfo {
  struct MHD_PostProcessor *postprocessor;
  MHD_Connection *connection;
  stringstream request;
  HttpServer *server;
  int code;
};

HttpServer::HttpServer(int port, const std::string &sslcert,
                       const std::string &sslkey, int threads)
    : AbstractServerConnector(), port(port), threads(threads), running(false),
      path_sslcert(sslcert), path_sslkey(sslkey), daemon(NULL) {}

HttpServer::~HttpServer() {}

bool HttpServer::SetBindAddress(const std::string &addr) {

  bind_address.sin_family = AF_INET;
  bind_address.sin_port = htons(this->port);

  if (addr == "")
    bind_address.sin_addr.s_addr = htonl(INADDR_ANY);
  else
    inet_aton("127.0.0.1", (struct in_addr *)&bind_address.sin_addr.s_addr);
  return true;
}

IClientConnectionHandler *HttpServer::GetHandler(const std::string &url) {
  if (AbstractServerConnector::GetHandler() != NULL)
    return AbstractServerConnector::GetHandler();
  map<string, IClientConnectionHandler *>::iterator it =
      this->urlhandler.find(url);
  if (it != this->urlhandler.end())
    return it->second;
  return NULL;
}

bool HttpServer::StartListening() {
  if (!this->running) {
    const bool has_epoll =
        (MHD_is_feature_supported(MHD_FEATURE_EPOLL) == MHD_YES);
    const bool has_poll =
        (MHD_is_feature_supported(MHD_FEATURE_POLL) == MHD_YES);
    unsigned int mhd_flags;

    SetBindAddress("");

    if (has_epoll)
// In MHD version 0.9.44 the flag is renamed to
// MHD_USE_EPOLL_INTERNALLY_LINUX_ONLY. In later versions both
// are deprecated.
#if defined(MHD_USE_EPOLL_INTERNALLY)
      mhd_flags = MHD_USE_EPOLL_INTERNALLY;
#else
      mhd_flags = MHD_USE_EPOLL_INTERNALLY_LINUX_ONLY;
#endif
    else if (has_poll)
      mhd_flags = MHD_USE_POLL_INTERNALLY;
    if (this->path_sslcert != "" && this->path_sslkey != "") {
      try {
        SpecificationParser::GetFileContent(this->path_sslcert, this->sslcert);
        SpecificationParser::GetFileContent(this->path_sslkey, this->sslkey);

        this->daemon = MHD_start_daemon(
            MHD_USE_SSL | mhd_flags, this->port, NULL, NULL,
            HttpServer::callback, this, MHD_OPTION_HTTPS_MEM_KEY,
            this->sslkey.c_str(), MHD_OPTION_HTTPS_MEM_CERT,
            this->sslcert.c_str(), MHD_OPTION_THREAD_POOL_SIZE, this->threads,
            MHD_OPTION_SOCK_ADDR, &bind_address, MHD_OPTION_END);
      } catch (JsonRpcException &ex) {
        return false;
      }
    } else {
      this->daemon = MHD_start_daemon(
          mhd_flags, this->port, NULL, NULL, HttpServer::callback, this,
          MHD_OPTION_THREAD_POOL_SIZE, this->threads, MHD_OPTION_SOCK_ADDR,
          &bind_address, MHD_OPTION_END);
    }
    if (this->daemon != NULL)
      this->running = true;
  }
  return this->running;
}

bool HttpServer::StopListening() {
  if (this->running) {
    MHD_stop_daemon(this->daemon);
    this->running = false;
  }
  return true;
}

bool HttpServer::SendResponse(const string &response, void *addInfo) {
  struct mhd_coninfo *client_connection =
      static_cast<struct mhd_coninfo *>(addInfo);
  struct MHD_Response *result = MHD_create_response_from_buffer(
      response.size(), (void *)response.c_str(), MHD_RESPMEM_MUST_COPY);

  MHD_add_response_header(result, "Content-Type", "application/json");
  MHD_add_response_header(result, "Access-Control-Allow-Origin", "*");

  int ret = MHD_queue_response(client_connection->connection,
                               client_connection->code, result);
  MHD_destroy_response(result);
  return ret == MHD_YES;
}

bool HttpServer::SendOptionsResponse(void *addInfo) {
  struct mhd_coninfo *client_connection =
      static_cast<struct mhd_coninfo *>(addInfo);
  struct MHD_Response *result =
      MHD_create_response_from_buffer(0, NULL, MHD_RESPMEM_MUST_COPY);

  MHD_add_response_header(result, "Allow", "POST, OPTIONS");
  MHD_add_response_header(result, "Access-Control-Allow-Origin", "*");
  MHD_add_response_header(result, "Access-Control-Allow-Headers",
                          "origin, content-type, accept");
  MHD_add_response_header(result, "DAV", "1");

  int ret = MHD_queue_response(client_connection->connection,
                               client_connection->code, result);
  MHD_destroy_response(result);
  return ret == MHD_YES;
}

void HttpServer::SetUrlHandler(const string &url,
                               IClientConnectionHandler *handler) {
  this->urlhandler[url] = handler;
  this->SetHandler(NULL);
}

int HttpServer::callback(void *cls, MHD_Connection *connection, const char *url,
                         const char *method, const char *version,
                         const char *upload_data, size_t *upload_data_size,
                         void **con_cls) {
  (void)version;
  if (*con_cls == NULL) {
    struct mhd_coninfo *client_connection = new mhd_coninfo;
    client_connection->connection = connection;
    client_connection->server = static_cast<HttpServer *>(cls);
    *con_cls = client_connection;
    return MHD_YES;
  }
  struct mhd_coninfo *client_connection =
      static_cast<struct mhd_coninfo *>(*con_cls);

  if (string("POST") == method) {
    if (*upload_data_size != 0) {
      client_connection->request.write(upload_data, *upload_data_size);
      *upload_data_size = 0;
      return MHD_YES;
    } else {
      string response;
      IClientConnectionHandler *handler =
          client_connection->server->GetHandler(string(url));
      if (handler == NULL) {
        client_connection->code = MHD_HTTP_INTERNAL_SERVER_ERROR;
        client_connection->server->SendResponse(
            "No client connection handler found", client_connection);
      } else {
        client_connection->code = MHD_HTTP_OK;
        handler->HandleRequest(client_connection->request.str(), response);
        client_connection->server->SendResponse(response, client_connection);
      }
    }
  } else if (string("OPTIONS") == method) {
    client_connection->code = MHD_HTTP_OK;
    client_connection->server->SendOptionsResponse(client_connection);
  } else {
    client_connection->code = MHD_HTTP_METHOD_NOT_ALLOWED;
    client_connection->server->SendResponse("Not allowed HTTP Method",
                                            client_connection);
  }
  delete client_connection;
  *con_cls = NULL;

  return MHD_YES;
}
<commit_msg>Fix bind addr string<commit_after>/*************************************************************************
 * libjson-rpc-cpp
 *************************************************************************
 * @file    httpserver.cpp
 * @date    31.12.2012
 * @author  Peter Spiess-Knafl <dev@spiessknafl.at>
 * @license See attached LICENSE.txt
 ************************************************************************/

#include "httpserver.h"
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <jsonrpccpp/common/specificationparser.h>
#include <sstream>

using namespace jsonrpc;
using namespace std;

#define BUFFERSIZE 65536

struct mhd_coninfo {
  struct MHD_PostProcessor *postprocessor;
  MHD_Connection *connection;
  stringstream request;
  HttpServer *server;
  int code;
};

HttpServer::HttpServer(int port, const std::string &sslcert,
                       const std::string &sslkey, int threads)
    : AbstractServerConnector(), port(port), threads(threads), running(false),
      path_sslcert(sslcert), path_sslkey(sslkey), daemon(NULL) {}

HttpServer::~HttpServer() {}

bool HttpServer::SetBindAddress(const std::string &addr) {

  bind_address.sin_family = AF_INET;
  bind_address.sin_port = htons(this->port);

  if (addr == "")
    bind_address.sin_addr.s_addr = htonl(INADDR_ANY);
  else
    inet_aton(addr.c_str(), (struct in_addr *)&bind_address.sin_addr.s_addr);
  return true;
}

IClientConnectionHandler *HttpServer::GetHandler(const std::string &url) {
  if (AbstractServerConnector::GetHandler() != NULL)
    return AbstractServerConnector::GetHandler();
  map<string, IClientConnectionHandler *>::iterator it =
      this->urlhandler.find(url);
  if (it != this->urlhandler.end())
    return it->second;
  return NULL;
}

bool HttpServer::StartListening() {
  if (!this->running) {
    const bool has_epoll =
        (MHD_is_feature_supported(MHD_FEATURE_EPOLL) == MHD_YES);
    const bool has_poll =
        (MHD_is_feature_supported(MHD_FEATURE_POLL) == MHD_YES);
    unsigned int mhd_flags;

    SetBindAddress("");

    if (has_epoll)
// In MHD version 0.9.44 the flag is renamed to
// MHD_USE_EPOLL_INTERNALLY_LINUX_ONLY. In later versions both
// are deprecated.
#if defined(MHD_USE_EPOLL_INTERNALLY)
      mhd_flags = MHD_USE_EPOLL_INTERNALLY;
#else
      mhd_flags = MHD_USE_EPOLL_INTERNALLY_LINUX_ONLY;
#endif
    else if (has_poll)
      mhd_flags = MHD_USE_POLL_INTERNALLY;
    if (this->path_sslcert != "" && this->path_sslkey != "") {
      try {
        SpecificationParser::GetFileContent(this->path_sslcert, this->sslcert);
        SpecificationParser::GetFileContent(this->path_sslkey, this->sslkey);

        this->daemon = MHD_start_daemon(
            MHD_USE_SSL | mhd_flags, this->port, NULL, NULL,
            HttpServer::callback, this, MHD_OPTION_HTTPS_MEM_KEY,
            this->sslkey.c_str(), MHD_OPTION_HTTPS_MEM_CERT,
            this->sslcert.c_str(), MHD_OPTION_THREAD_POOL_SIZE, this->threads,
            MHD_OPTION_SOCK_ADDR, &bind_address, MHD_OPTION_END);
      } catch (JsonRpcException &ex) {
        return false;
      }
    } else {
      this->daemon = MHD_start_daemon(
          mhd_flags, this->port, NULL, NULL, HttpServer::callback, this,
          MHD_OPTION_THREAD_POOL_SIZE, this->threads, MHD_OPTION_SOCK_ADDR,
          &bind_address, MHD_OPTION_END);
    }
    if (this->daemon != NULL)
      this->running = true;
  }
  return this->running;
}

bool HttpServer::StopListening() {
  if (this->running) {
    MHD_stop_daemon(this->daemon);
    this->running = false;
  }
  return true;
}

bool HttpServer::SendResponse(const string &response, void *addInfo) {
  struct mhd_coninfo *client_connection =
      static_cast<struct mhd_coninfo *>(addInfo);
  struct MHD_Response *result = MHD_create_response_from_buffer(
      response.size(), (void *)response.c_str(), MHD_RESPMEM_MUST_COPY);

  MHD_add_response_header(result, "Content-Type", "application/json");
  MHD_add_response_header(result, "Access-Control-Allow-Origin", "*");

  int ret = MHD_queue_response(client_connection->connection,
                               client_connection->code, result);
  MHD_destroy_response(result);
  return ret == MHD_YES;
}

bool HttpServer::SendOptionsResponse(void *addInfo) {
  struct mhd_coninfo *client_connection =
      static_cast<struct mhd_coninfo *>(addInfo);
  struct MHD_Response *result =
      MHD_create_response_from_buffer(0, NULL, MHD_RESPMEM_MUST_COPY);

  MHD_add_response_header(result, "Allow", "POST, OPTIONS");
  MHD_add_response_header(result, "Access-Control-Allow-Origin", "*");
  MHD_add_response_header(result, "Access-Control-Allow-Headers",
                          "origin, content-type, accept");
  MHD_add_response_header(result, "DAV", "1");

  int ret = MHD_queue_response(client_connection->connection,
                               client_connection->code, result);
  MHD_destroy_response(result);
  return ret == MHD_YES;
}

void HttpServer::SetUrlHandler(const string &url,
                               IClientConnectionHandler *handler) {
  this->urlhandler[url] = handler;
  this->SetHandler(NULL);
}

int HttpServer::callback(void *cls, MHD_Connection *connection, const char *url,
                         const char *method, const char *version,
                         const char *upload_data, size_t *upload_data_size,
                         void **con_cls) {
  (void)version;
  if (*con_cls == NULL) {
    struct mhd_coninfo *client_connection = new mhd_coninfo;
    client_connection->connection = connection;
    client_connection->server = static_cast<HttpServer *>(cls);
    *con_cls = client_connection;
    return MHD_YES;
  }
  struct mhd_coninfo *client_connection =
      static_cast<struct mhd_coninfo *>(*con_cls);

  if (string("POST") == method) {
    if (*upload_data_size != 0) {
      client_connection->request.write(upload_data, *upload_data_size);
      *upload_data_size = 0;
      return MHD_YES;
    } else {
      string response;
      IClientConnectionHandler *handler =
          client_connection->server->GetHandler(string(url));
      if (handler == NULL) {
        client_connection->code = MHD_HTTP_INTERNAL_SERVER_ERROR;
        client_connection->server->SendResponse(
            "No client connection handler found", client_connection);
      } else {
        client_connection->code = MHD_HTTP_OK;
        handler->HandleRequest(client_connection->request.str(), response);
        client_connection->server->SendResponse(response, client_connection);
      }
    }
  } else if (string("OPTIONS") == method) {
    client_connection->code = MHD_HTTP_OK;
    client_connection->server->SendOptionsResponse(client_connection);
  } else {
    client_connection->code = MHD_HTTP_METHOD_NOT_ALLOWED;
    client_connection->server->SendResponse("Not allowed HTTP Method",
                                            client_connection);
  }
  delete client_connection;
  *con_cls = NULL;

  return MHD_YES;
}
<|endoftext|>


<commit_before>/*
 * Test Driver for Botan
 */

#include <vector>
#include <string>

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <exception>
#include <limits>

#include <botan/botan.h>
#include <botan/mp_types.h>

using namespace Botan_types;

#include "getopt.h"

const std::string VALIDATION_FILE = "checks/validate.dat";
const std::string BIGINT_VALIDATION_FILE = "checks/mp_valid.dat";
const std::string PK_VALIDATION_FILE = "checks/pk_valid.dat";
const std::string EXPECTED_FAIL_FILE = "checks/fail.dat";

void benchmark(const std::string&, bool html, double seconds);
void bench_pk(const std::string&, bool html, double seconds);
u32bit bench_algo(const std::string&, double);
int validate();
void print_help();

int main(int argc, char* argv[])
   {
   try
      {
      OptionParser opts("help|html|init=|validate|"
                        "benchmark|bench-type=|bench-algo=|seconds=");
      opts.parse(argv);

      std::string init_flags = (opts.is_set("init") ? opts.value("init") : "");

      Botan::InitializerOptions init_options(init_flags);
      Botan::LibraryInitializer init(init_options);

      if(opts.is_set("help") || argc <= 1)
         { print_help(); return 1; }
      if(opts.is_set("validate"))
         return validate();

      double seconds = 1.5;

      if(opts.is_set("seconds"))
         {
         seconds = std::atof(opts.value("seconds").c_str());
         if((seconds < 0.1 || seconds > 30) && seconds != 0)
            {
            std::cout << "Invalid argument to --seconds\n";
            return 2;
            }
         }

      if(opts.is_set("bench-algo"))
         {
         const std::string alg = opts.value("bench-algo");
         u32bit found = bench_algo(alg, seconds);
         if(!found) // maybe it's a PK algorithm
            bench_pk(alg, false, seconds);
         }

      const bool html = opts.is_set("html");

      if(opts.is_set("benchmark"))
         benchmark("All", html, seconds);
      else if(opts.is_set("bench-type"))
         {
         const std::string type = opts.value("bench-type");

         if(type == "all")
            benchmark("All", html, seconds);
         else if(type == "block")
            benchmark("Block Cipher", html, seconds);
         else if(type == "stream")
            benchmark("Stream Cipher", html, seconds);
         else if(type == "hash")
            benchmark("Hash", html, seconds);
         else if(type == "mac")
            benchmark("MAC", html, seconds);
         else if(type == "rng")
            benchmark("RNG", html, seconds);
         else if(type == "pk")
            bench_pk("All", html, seconds);
         }
      }
   catch(Botan::Exception& e)
      {
      std::cout << "Exception caught:\n   " << e.what() << std::endl;
      return 1;
      }
   catch(std::exception& e)
      {
      std::cout << "Standard library exception caught:\n   "
                << e.what() << std::endl;
      return 1;
      }
   catch(...)
      {
      std::cout << "Unknown exception caught." << std::endl;
      return 1;
      }

   return 0;
   }

void print_help()
   {
   std::cout << Botan::version_string() << " test driver" << std::endl
      << "Usage:\n"
      << "  --validate: Check test vectors\n"
      << "  --benchmark: Benchmark everything\n"
      << "  --bench-type={block,mode,stream,hash,mac,rng,pk}:\n"
      << "         Benchmark only algorithms of a particular type\n"
      << "  --html: Produce HTML output for benchmarks\n"
      << "  --seconds=n: Benchmark for n seconds\n"
      << "  --help: Print this message\n";
   }

int validate()
   {
   void test_types();
   u32bit do_validation_tests(const std::string&, bool = true);
   u32bit do_bigint_tests(const std::string&);
   u32bit do_pk_validation_tests(const std::string&);

   std::cout << "Beginning validation tests..." << std::endl;

   test_types();
   u32bit errors = 0;
   try {
      errors += do_validation_tests(VALIDATION_FILE);
      errors += do_validation_tests(EXPECTED_FAIL_FILE, false);
      errors += do_bigint_tests(BIGINT_VALIDATION_FILE);
      errors += do_pk_validation_tests(PK_VALIDATION_FILE);
      }
   catch(Botan::Exception& e)
      {
      std::cout << "Exception caught: " << e.what() << std::endl;
      return 1;
      }
   catch(std::exception& e)
      {
      std::cout << "Standard library exception caught: "
                << e.what() << std::endl;
      return 1;
      }
   catch(...)
      {
      std::cout << "Unknown exception caught." << std::endl;
      return 1;
      }

   if(errors)
      {
      std::cout << errors << " test"  << ((errors == 1) ? "" : "s")
                << " failed." << std::endl;
      return 1;
      }

   std::cout << "All tests passed!" << std::endl;
   return 0;
   }

template<typename T>
bool test(const char* type, int digits, bool is_signed)
   {
   bool passed = true;
   if(std::numeric_limits<T>::is_specialized == false)
      {
      std::cout << "WARNING: Could not check parameters of " << type
                << " in std::numeric_limits" << std::endl;
      return true;
      }

   if(std::numeric_limits<T>::digits != digits && digits != 0)
      {
      std::cout << "ERROR: numeric_limits<" << type << ">::digits != "
                << digits << std::endl;
      passed = false;
      }
   if(std::numeric_limits<T>::is_signed != is_signed)
      {
      std::cout << "ERROR: numeric_limits<" << type << ">::is_signed != "
                << std::boolalpha << is_signed << std::endl;
      passed = false;
      }
   if(std::numeric_limits<T>::is_integer == false)
      {
      std::cout << "ERROR: numeric_limits<" << type
                << ">::is_integer == false " << std::endl;
      passed = false;
      }
   return passed;
   }

void test_types()
   {
   bool passed = true;

   passed = passed && test<Botan::byte  >("byte",    8, false);
   passed = passed && test<Botan::u16bit>("u16bit", 16, false);
   passed = passed && test<Botan::u32bit>("u32bit", 32, false);
   passed = passed && test<Botan::u64bit>("u64bit", 64, false);
   passed = passed && test<Botan::s32bit>("s32bit", 31,  true);
   passed = passed && test<Botan::word>("word", 0, false);

   if(!passed)
      {
      std::cout << "Important settings in types.h are wrong. Please fix "
                   "and recompile." << std::endl;
      std::exit(1);
      }
   }
<commit_msg>Allow --bench-algo to take multiple arguments<commit_after>/*
 * Test Driver for Botan
 */

#include <vector>
#include <string>

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <exception>
#include <limits>

#include <botan/botan.h>
#include <botan/mp_types.h>

using namespace Botan_types;

#include "getopt.h"

const std::string VALIDATION_FILE = "checks/validate.dat";
const std::string BIGINT_VALIDATION_FILE = "checks/mp_valid.dat";
const std::string PK_VALIDATION_FILE = "checks/pk_valid.dat";
const std::string EXPECTED_FAIL_FILE = "checks/fail.dat";

void benchmark(const std::string&, bool html, double seconds);
void bench_pk(const std::string&, bool html, double seconds);
u32bit bench_algo(const std::string&, double);
int validate();
void print_help();

int main(int argc, char* argv[])
   {
   try
      {
      OptionParser opts("help|html|init=|validate|"
                        "benchmark|bench-type=|bench-algo=|seconds=");
      opts.parse(argv);

      std::string init_flags = (opts.is_set("init") ? opts.value("init") : "");

      Botan::InitializerOptions init_options(init_flags);
      Botan::LibraryInitializer init(init_options);

      if(opts.is_set("help") || argc <= 1)
         { print_help(); return 1; }
      if(opts.is_set("validate"))
         return validate();

      double seconds = 1.5;

      if(opts.is_set("seconds"))
         {
         seconds = std::atof(opts.value("seconds").c_str());
         if((seconds < 0.1 || seconds > 30) && seconds != 0)
            {
            std::cout << "Invalid argument to --seconds\n";
            return 2;
            }
         }

      if(opts.is_set("bench-algo"))
         {
         std::vector<std::string> algs =
            Botan::split_on(opts.value("bench-algo"), ',');

         for(u32bit j = 0; j != algs.size(); j++)
            {
            const std::string alg = algs[j];
            u32bit found = bench_algo(alg, seconds);
            if(!found) // maybe it's a PK algorithm
               bench_pk(alg, false, seconds);
            }
         }

      const bool html = opts.is_set("html");

      if(opts.is_set("benchmark"))
         benchmark("All", html, seconds);
      else if(opts.is_set("bench-type"))
         {
         const std::string type = opts.value("bench-type");

         if(type == "all")
            benchmark("All", html, seconds);
         else if(type == "block")
            benchmark("Block Cipher", html, seconds);
         else if(type == "stream")
            benchmark("Stream Cipher", html, seconds);
         else if(type == "hash")
            benchmark("Hash", html, seconds);
         else if(type == "mac")
            benchmark("MAC", html, seconds);
         else if(type == "rng")
            benchmark("RNG", html, seconds);
         else if(type == "pk")
            bench_pk("All", html, seconds);
         }
      }
   catch(Botan::Exception& e)
      {
      std::cout << "Exception caught:\n   " << e.what() << std::endl;
      return 1;
      }
   catch(std::exception& e)
      {
      std::cout << "Standard library exception caught:\n   "
                << e.what() << std::endl;
      return 1;
      }
   catch(...)
      {
      std::cout << "Unknown exception caught." << std::endl;
      return 1;
      }

   return 0;
   }

void print_help()
   {
   std::cout << Botan::version_string() << " test driver" << std::endl
      << "Usage:\n"
      << "  --validate: Check test vectors\n"
      << "  --benchmark: Benchmark everything\n"
      << "  --bench-type={block,mode,stream,hash,mac,rng,pk}:\n"
      << "         Benchmark only algorithms of a particular type\n"
      << "  --html: Produce HTML output for benchmarks\n"
      << "  --seconds=n: Benchmark for n seconds\n"
      << "  --help: Print this message\n";
   }

int validate()
   {
   void test_types();
   u32bit do_validation_tests(const std::string&, bool = true);
   u32bit do_bigint_tests(const std::string&);
   u32bit do_pk_validation_tests(const std::string&);

   std::cout << "Beginning validation tests..." << std::endl;

   test_types();
   u32bit errors = 0;
   try {
      errors += do_validation_tests(VALIDATION_FILE);
      errors += do_validation_tests(EXPECTED_FAIL_FILE, false);
      errors += do_bigint_tests(BIGINT_VALIDATION_FILE);
      errors += do_pk_validation_tests(PK_VALIDATION_FILE);
      }
   catch(Botan::Exception& e)
      {
      std::cout << "Exception caught: " << e.what() << std::endl;
      return 1;
      }
   catch(std::exception& e)
      {
      std::cout << "Standard library exception caught: "
                << e.what() << std::endl;
      return 1;
      }
   catch(...)
      {
      std::cout << "Unknown exception caught." << std::endl;
      return 1;
      }

   if(errors)
      {
      std::cout << errors << " test"  << ((errors == 1) ? "" : "s")
                << " failed." << std::endl;
      return 1;
      }

   std::cout << "All tests passed!" << std::endl;
   return 0;
   }

template<typename T>
bool test(const char* type, int digits, bool is_signed)
   {
   bool passed = true;
   if(std::numeric_limits<T>::is_specialized == false)
      {
      std::cout << "WARNING: Could not check parameters of " << type
                << " in std::numeric_limits" << std::endl;
      return true;
      }

   if(std::numeric_limits<T>::digits != digits && digits != 0)
      {
      std::cout << "ERROR: numeric_limits<" << type << ">::digits != "
                << digits << std::endl;
      passed = false;
      }
   if(std::numeric_limits<T>::is_signed != is_signed)
      {
      std::cout << "ERROR: numeric_limits<" << type << ">::is_signed != "
                << std::boolalpha << is_signed << std::endl;
      passed = false;
      }
   if(std::numeric_limits<T>::is_integer == false)
      {
      std::cout << "ERROR: numeric_limits<" << type
                << ">::is_integer == false " << std::endl;
      passed = false;
      }
   return passed;
   }

void test_types()
   {
   bool passed = true;

   passed = passed && test<Botan::byte  >("byte",    8, false);
   passed = passed && test<Botan::u16bit>("u16bit", 16, false);
   passed = passed && test<Botan::u32bit>("u32bit", 32, false);
   passed = passed && test<Botan::u64bit>("u64bit", 64, false);
   passed = passed && test<Botan::s32bit>("s32bit", 31,  true);
   passed = passed && test<Botan::word>("word", 0, false);

   if(!passed)
      {
      std::cout << "Important settings in types.h are wrong. Please fix "
                   "and recompile." << std::endl;
      std::exit(1);
      }
   }
<|endoftext|>


<commit_before>/* Copyright (C) 2003 Scott Wheeler <wheeler@kde.org>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <iostream>

#include <tbytevector.h>
#include <tbytevectorlist.h>
#include <tstring.h>
#include <tlist.h>
#include <tdebug.h>

#include <id3v2synchdata.h>

using namespace TagLib;
using namespace std;

void testString();
void testByteVector();
void testSynchData();
void testList();

static int resultCount = 1;

int main()
{
  testString();
  resultCount = 1;
  testByteVector();
  resultCount = 1;
  testSynchData();
  resultCount = 1;
  testList();

  return 0;
}

void printResult(bool result)
{
  if(result)
    cout << "(" << resultCount << ")\tpass" << endl;
  else
    cout << "(" << resultCount << ")\tFAIL" << endl;

  resultCount++;
}

void testString()
{
  cout << "*** Testing TagLib::String ***" << endl;

  String s = "taglib string";
  ByteVector v = "taglib string";
  printResult(v == s.data(String::Latin1));

  char str[] = "taglib string";
  printResult(strcmp(s.toCString(), str) == 0);

  String unicode("José Carlos", String::UTF8);
  printResult(strcmp(unicode.toCString(), "Jos Carlos") == 0);

  String latin = "Jos Carlos";
  printResult(strcmp(latin.toCString(true), "José Carlos") == 0);

  String unicode2(unicode.to8Bit(true), String::UTF8);
  printResult(unicode == unicode2);

  printResult(strcmp(String::number(0).toCString(), "0") == 0);
  printResult(strcmp(String::number(12345678).toCString(), "12345678") == 0);
  printResult(strcmp(String::number(-12345678).toCString(), "-12345678") == 0);

  String n = "123";
  printResult(n.toInt() == 123);

  n = "-123";
  printResult(n.toInt() == -123);

  printResult(String("0").toInt() == 0);
  printResult(String("1").toInt() == 1);

  printResult(String("  foo  ").stripWhiteSpace() == String("foo"));
  printResult(String("foo    ").stripWhiteSpace() == String("foo"));
  printResult(String("    foo").stripWhiteSpace() == String("foo"));

  printResult(memcmp(String("foo").data(String::Latin1).data(), "foo", 3) == 0);
  printResult(memcmp(String("f").data(String::Latin1).data(), "f", 1) == 0);
}

void testConversion(unsigned int i, unsigned char a, unsigned char b, unsigned char c, unsigned char d)
{
  ByteVector v(4, 0);

  v[3] = a;
  v[2] = b;
  v[1] = c;
  v[0] = d;
  printResult(v.toUInt(false) == i);

  v[0] = a;
  v[1] = b;
  v[2] = c;
  v[3] = d;
  printResult(v.toUInt() == i);
}

void testByteVector()
{
  cout << "*** Testing TagLib::ByteVector ***" << endl;
  ByteVector v("foobar");

  printResult(v.find("ob") == 2);
  printResult(v.find('b') == 3);

  ByteVector n(4, 0);
  n[0] = 1;
  printResult(n.toUInt(true) == 16777216);
  printResult(n.toUInt(false) == 1);
  printResult(ByteVector::fromUInt(16777216, true) == n);
  printResult(ByteVector::fromUInt(1, false) == n);

  printResult(ByteVector::fromUInt(0xa0).toUInt() == 0xa0);

  testConversion(0x000000a0, 0x00, 0x00, 0x00, 0xa0);
  testConversion(0xd50bf072, 0xd5, 0x0b, 0xf0, 0x72);

  ByteVector r0("**************");
  ByteVector r1("OggS**********");
  ByteVector r2("**********OggS");
  ByteVector r3("OggS******OggS");
  ByteVector r4("OggS*OggS*OggS");

  printResult(r0.find("OggS") == -1);
  printResult(r0.rfind("OggS") == -1);
  printResult(r1.find("OggS") == r1.rfind("OggS"));
  printResult(r2.find("OggS") == r2.rfind("OggS"));
  printResult(r3.find("OggS") == 0);
  printResult(r3.rfind("OggS") == 10);
  printResult(r4.rfind("OggS") == 10);
  printResult(r4.rfind("OggS", 12) == 5);

  printResult(ByteVector::fromLongLong(1).toLongLong() == 1);
  printResult(ByteVector::fromLongLong(0).toLongLong() == 0);
  printResult(ByteVector::fromLongLong(0xffffffffffffffffLL).toLongLong() == -1);
  printResult(ByteVector::fromLongLong(0xfffffffffffffffeLL).toLongLong() == -2);
  printResult(ByteVector::fromLongLong(1024).toLongLong() == 1024);

  ByteVector a1("foo");
  a1.append("bar");
  printResult(a1 == "foobar");

  ByteVector a2("foo");
  a2.append("b");
  printResult(a2 == "foob");

  ByteVector a3;
  a3.append("b");
  printResult(a3 == "b");

  ByteVector s1("foo");
  printResult(ByteVectorList::split(s1, " ").size() == 1);

  ByteVector s2("f");
  printResult(ByteVectorList::split(s2, " ").size() == 1);
}

void testSynchData()
{
  cout << "*** Testing TagLib::ID3v2::SynchData ***" << endl;

  { // test 1
    char data[] = { 0, 0, 0, 127 };
    ByteVector v(data, 4);

    printResult(ID3v2::SynchData::toUInt(v) == 127);
    printResult(ID3v2::SynchData::fromUInt(127) == v);
  }
  { // test 2
    char data[] = { 0, 0, 1, 0 };
    ByteVector v(data, 4);

    printResult(ID3v2::SynchData::toUInt(v) == 128);
    printResult(ID3v2::SynchData::fromUInt(128) == v);
  }
  { // test 3
    char data[] = { 0, 0, 1, 1 };
    ByteVector v(data, 4);

    printResult(ID3v2::SynchData::toUInt(v) == 129);
    printResult(ID3v2::SynchData::fromUInt(129) == v);
  }
}

void testList()
{
  cout << "*** Testing TagLib::List<T> ***" << endl;
  List<int> l1;
  List<int> l2;
  List<int> l3;
  l1.append(1);
  l1.append(2);
  l2.append(3);
  l2.append(4);
  l1.append(l2);
  l3.append(1);
  l3.append(2);
  l3.append(3);
  l3.append(4);
  printResult(l1 == l3);
}
<commit_msg>Add a couple of testcases that point out UTF16 bugs.<commit_after>/* Copyright (C) 2003 Scott Wheeler <wheeler@kde.org>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <iostream>

#include <tbytevector.h>
#include <tbytevectorlist.h>
#include <tstring.h>
#include <tlist.h>
#include <tdebug.h>

#include <id3v2synchdata.h>

using namespace TagLib;
using namespace std;

void testString();
void testByteVector();
void testSynchData();
void testList();

static int resultCount = 1;

int main()
{
  testString();
  resultCount = 1;
  testByteVector();
  resultCount = 1;
  testSynchData();
  resultCount = 1;
  testList();

  return 0;
}

void printResult(bool result)
{
  if(result)
    cout << "(" << resultCount << ")\tpass" << endl;
  else
    cout << "(" << resultCount << ")\tFAIL" << endl;

  resultCount++;
}

void testString()
{
  cout << "*** Testing TagLib::String ***" << endl;

  String s = "taglib string";
  ByteVector v = "taglib string";
  printResult(v == s.data(String::Latin1));

  char str[] = "taglib string";
  printResult(strcmp(s.toCString(), str) == 0);

  String unicode("José Carlos", String::UTF8);
  printResult(strcmp(unicode.toCString(), "Jos Carlos") == 0);

  String latin = "Jos Carlos";
  printResult(strcmp(latin.toCString(true), "José Carlos") == 0);

  String unicode2(unicode.to8Bit(true), String::UTF8);
  printResult(unicode == unicode2);

  printResult(strcmp(String::number(0).toCString(), "0") == 0);
  printResult(strcmp(String::number(12345678).toCString(), "12345678") == 0);
  printResult(strcmp(String::number(-12345678).toCString(), "-12345678") == 0);

  String n = "123";
  printResult(n.toInt() == 123);

  n = "-123";
  printResult(n.toInt() == -123);

  printResult(String("0").toInt() == 0);
  printResult(String("1").toInt() == 1);

  printResult(String("  foo  ").stripWhiteSpace() == String("foo"));
  printResult(String("foo    ").stripWhiteSpace() == String("foo"));
  printResult(String("    foo").stripWhiteSpace() == String("foo"));

  printResult(memcmp(String("foo").data(String::Latin1).data(), "foo", 3) == 0);
  printResult(memcmp(String("f").data(String::Latin1).data(), "f", 1) == 0);

  ByteVector utf16 = unicode.data(String::UTF16);

  // Check to make sure that the BOM is there and that the data size is correct

  printResult(utf16.size() == 2 + (unicode.size() * 2));

  printResult(unicode == String(utf16, String::UTF16));
}

void testConversion(unsigned int i, unsigned char a, unsigned char b, unsigned char c, unsigned char d)
{
  ByteVector v(4, 0);

  v[3] = a;
  v[2] = b;
  v[1] = c;
  v[0] = d;
  printResult(v.toUInt(false) == i);

  v[0] = a;
  v[1] = b;
  v[2] = c;
  v[3] = d;
  printResult(v.toUInt() == i);
}

void testByteVector()
{
  cout << "*** Testing TagLib::ByteVector ***" << endl;
  ByteVector v("foobar");

  printResult(v.find("ob") == 2);
  printResult(v.find('b') == 3);

  ByteVector n(4, 0);
  n[0] = 1;
  printResult(n.toUInt(true) == 16777216);
  printResult(n.toUInt(false) == 1);
  printResult(ByteVector::fromUInt(16777216, true) == n);
  printResult(ByteVector::fromUInt(1, false) == n);

  printResult(ByteVector::fromUInt(0xa0).toUInt() == 0xa0);

  testConversion(0x000000a0, 0x00, 0x00, 0x00, 0xa0);
  testConversion(0xd50bf072, 0xd5, 0x0b, 0xf0, 0x72);

  ByteVector r0("**************");
  ByteVector r1("OggS**********");
  ByteVector r2("**********OggS");
  ByteVector r3("OggS******OggS");
  ByteVector r4("OggS*OggS*OggS");

  printResult(r0.find("OggS") == -1);
  printResult(r0.rfind("OggS") == -1);
  printResult(r1.find("OggS") == r1.rfind("OggS"));
  printResult(r2.find("OggS") == r2.rfind("OggS"));
  printResult(r3.find("OggS") == 0);
  printResult(r3.rfind("OggS") == 10);
  printResult(r4.rfind("OggS") == 10);
  printResult(r4.rfind("OggS", 12) == 5);

  printResult(ByteVector::fromLongLong(1).toLongLong() == 1);
  printResult(ByteVector::fromLongLong(0).toLongLong() == 0);
  printResult(ByteVector::fromLongLong(0xffffffffffffffffLL).toLongLong() == -1);
  printResult(ByteVector::fromLongLong(0xfffffffffffffffeLL).toLongLong() == -2);
  printResult(ByteVector::fromLongLong(1024).toLongLong() == 1024);

  ByteVector a1("foo");
  a1.append("bar");
  printResult(a1 == "foobar");

  ByteVector a2("foo");
  a2.append("b");
  printResult(a2 == "foob");

  ByteVector a3;
  a3.append("b");
  printResult(a3 == "b");

  ByteVector s1("foo");
  printResult(ByteVectorList::split(s1, " ").size() == 1);

  ByteVector s2("f");
  printResult(ByteVectorList::split(s2, " ").size() == 1);
}

void testSynchData()
{
  cout << "*** Testing TagLib::ID3v2::SynchData ***" << endl;

  { // test 1
    char data[] = { 0, 0, 0, 127 };
    ByteVector v(data, 4);

    printResult(ID3v2::SynchData::toUInt(v) == 127);
    printResult(ID3v2::SynchData::fromUInt(127) == v);
  }
  { // test 2
    char data[] = { 0, 0, 1, 0 };
    ByteVector v(data, 4);

    printResult(ID3v2::SynchData::toUInt(v) == 128);
    printResult(ID3v2::SynchData::fromUInt(128) == v);
  }
  { // test 3
    char data[] = { 0, 0, 1, 1 };
    ByteVector v(data, 4);

    printResult(ID3v2::SynchData::toUInt(v) == 129);
    printResult(ID3v2::SynchData::fromUInt(129) == v);
  }
}

void testList()
{
  cout << "*** Testing TagLib::List<T> ***" << endl;
  List<int> l1;
  List<int> l2;
  List<int> l3;
  l1.append(1);
  l1.append(2);
  l2.append(3);
  l2.append(4);
  l1.append(l2);
  l3.append(1);
  l3.append(2);
  l3.append(3);
  l3.append(4);
  printResult(l1 == l3);
}
<|endoftext|>


<commit_before>#include <boost/container/pmr/memory_resource.hpp>
#include <boost/core/no_exceptions_support.hpp>

#include <cstddef>

namespace boost {
namespace container {
namespace pmr {

class default_resource_impl : public memory_resource {
 public:
  virtual ~default_resource_impl() {}

  virtual void* do_allocate(std::size_t bytes, std::size_t alignment) { return std::malloc(bytes); }

  virtual void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) { std::free(p); }

  virtual bool do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT { return &other == this; }
} default_resource_instance;

memory_resource* new_delete_resource() BOOST_NOEXCEPT { return &default_resource_instance; }

memory_resource* set_default_resource(memory_resource* r) BOOST_NOEXCEPT {
  // Do nothing
  return &default_resource_instance;
}

memory_resource* get_default_resource() BOOST_NOEXCEPT { return &default_resource_instance; }

}  // namespace pmr
}  // namespace container
}  // namespace boost
<commit_msg>Fix missing cstdlib include (#237)<commit_after>#include <boost/container/pmr/memory_resource.hpp>
#include <boost/core/no_exceptions_support.hpp>

#include <cstddef>
#include <cstdlib>

namespace boost {
namespace container {
namespace pmr {

class default_resource_impl : public memory_resource {
 public:
  virtual ~default_resource_impl() {}

  virtual void* do_allocate(std::size_t bytes, std::size_t alignment) { return std::malloc(bytes); }

  virtual void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) { std::free(p); }

  virtual bool do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT { return &other == this; }
} default_resource_instance;

memory_resource* new_delete_resource() BOOST_NOEXCEPT { return &default_resource_instance; }

memory_resource* set_default_resource(memory_resource* r) BOOST_NOEXCEPT {
  // Do nothing
  return &default_resource_instance;
}

memory_resource* get_default_resource() BOOST_NOEXCEPT { return &default_resource_instance; }

}  // namespace pmr
}  // namespace container
}  // namespace boost
<|endoftext|>


<commit_before>// Authors: see AUTHORS.md at project root.
// CopyPolicy: released under the terms of the LGPLv2.1, see LICENSE at project root.
// URL: https://github.com/asrob-uc3m/robotDevastation

#include "YarpNetworkManager.hpp"

#include <sstream>
#include <cstring> // strcmp()

#include <yarp/os/Network.h>

#include <ColorDebug.hpp>

#include "Vocabs.hpp"

//-- Initialize static members
rd::YarpNetworkManager * rd::YarpNetworkManager::uniqueInstance = NULL;
const std::string rd::YarpNetworkManager::id = "YARP";
const int rd::YarpNetworkManager::KEEPALIVE_RATE_MS = 1000;

bool rd::YarpNetworkManager::RegisterManager()
{
    if (uniqueInstance == NULL)
    {
        uniqueInstance = new YarpNetworkManager();
    }

    return Register( uniqueInstance, id);
}

rd::YarpNetworkManager::YarpNetworkManager() : RateThread(KEEPALIVE_RATE_MS)
{
    started = false;
}

void rd::YarpNetworkManager::run()
{
    keepAlive();
}

rd::YarpNetworkManager::~YarpNetworkManager()
{
    uniqueInstance = NULL;
}

bool rd::YarpNetworkManager::start()
{
    if (player.getId() == -1)
    {
        CD_ERROR("NetworkManager not initialized, player id not set\n");
        return false;
    }

    if (started)
    {
        CD_ERROR("NetworkManager already started\n");
        return false;
    }

    yarp::os::Network::initMinimum();

    if ( ! yarp::os::Network::checkNetwork() )
    {
        CD_INFO_NO_HEADER("Checking for yarp network... ");
        CD_ERROR_NO_HEADER("[fail]\n");
        CD_INFO_NO_HEADER("Found no yarp network to connect to rdServer (try running \"yarpserver &\"), bye!\n");
        return false;
    }

    //-- Open the rpcClient port with this player's id
    std::ostringstream rpc_str;
    rpc_str << "/robotDevastation/";
    rpc_str << player.getId();
    rpc_str << "/rdServer/rpc:c";
    if( ! rpcClient.open( rpc_str.str() ) )
    {
        CD_ERROR("Could not open '%s'. Bye!\n",rpc_str.str().c_str());
        return false;
    }

    //-- Open the callback port with this player's id
    std::ostringstream callback_str;
    callback_str << "/robotDevastation/";
    callback_str << player.getId();
    callback_str << "/rdServer/info:i";
    if( ! callbackPort.open( callback_str.str() ) )
    {
        CD_ERROR("Could not open '%s'. Bye!\n",callback_str.str().c_str());
        return false;
    }

    //-- Connect robotDevastation RpcClient to rdServer RpcServer
    std::string rdServerRpcS("/rdServer/rpc:s");
    if( ! yarp::os::Network::connect( rpc_str.str() , rdServerRpcS ) )
    {
        CD_INFO_NO_HEADER("Checking for rdServer ports... ");
        CD_ERROR_NO_HEADER("[fail]\n");
        CD_INFO_NO_HEADER("Could not connect to rdServer '%s' port (try running \"rdServer &\"), bye!\n",rdServerRpcS.c_str());
        return false;
    }

    //-- Connect from rdServer info to robotDevastation callbackPort
    std::string rdServerInfoO("/rdServer/info:o");
    if ( ! yarp::os::Network::connect( rdServerInfoO, callback_str.str() ))
    {
        CD_INFO_NO_HEADER("Checking for rdServer ports... ");
        CD_ERROR_NO_HEADER("[fail]\n");
        CD_INFO_NO_HEADER("Could not connect from rdServer '%s' port (try running \"rdServer &\"), bye!\n",rdServerInfoO.c_str());
        return false;
    }
    CD_INFO_NO_HEADER("Checking for rdServer ports... ");
    CD_SUCCESS_NO_HEADER("[ok]\n");

    callbackPort.useCallback(*this);

    RateThread::start();

    started = true;
    return true;
}

void rd::YarpNetworkManager::onRead(yarp::os::Bottle &b)
{
    //CD_INFO("Got %s\n", b.toString().c_str());
    if ((b.get(0).asString() == "players")||(b.get(0).asVocab() == VOCAB_RD_PLAYERS)) {  // players //
        //CD_INFO("Number of players: %d\n",b.size()-1);  // -1 because of vocab.
        std::vector< Player > players;
        for (int i = 1; i < b.size(); i++)
        {
            Player rdPlayer(b.get(i).asList()->get(0).asInt(),
                              b.get(i).asList()->get(1).asString().c_str(),
                              b.get(i).asList()->get(2).asInt(),
                              b.get(i).asList()->get(3).asInt(),
                              b.get(i).asList()->get(4).asInt(),
                              b.get(i).asList()->get(5).asInt()
                              );
            players.push_back(rdPlayer);
        }

        //-- Notify listeners
        for (std::vector<NetworkEventListener *>::iterator it = listeners.begin(); it != listeners.end(); ++it)
        {
            (*it)->onDataArrived(players);
        }
    }
    else
    {
        CD_ERROR("What?\n");
    }

}

bool rd::YarpNetworkManager::stop()
{
    if (!started)
    {
        CD_ERROR("Already stopped\n");
        return false;
    }

    RateThread::askToStop();

    rpcClient.close();

    callbackPort.disableCallback();
    callbackPort.interrupt();
    callbackPort.close();

    yarp::os::NetworkBase::finiMinimum();

    started = false;
    return true;
}

bool rd::YarpNetworkManager::isStopped() const
{
    return !started;
}

bool rd::YarpNetworkManager::configure(const std::string & parameter, const Player & value)
{
    if (parameter.compare("player") == 0)
    {
        player = value;
        return true;
    }

    return NetworkManager::configure(parameter, value);
}

bool rd::YarpNetworkManager::sendPlayerHit(const Player & player, int damage)
{
    if (!started)
    {
        CD_ERROR("NetworkManager has not been started\n");
        return false;
    }

    //-- Send a message to the server with the player Id and the damage done:
    yarp::os::Bottle msg_player_hit, response;
    msg_player_hit.addVocab(VOCAB_RD_HIT);
    msg_player_hit.addInt(player.getId());
    msg_player_hit.addInt(damage);
    rpcClient.write(msg_player_hit,response);
    CD_INFO("rdServer response from hit: %s\n",response.toString().c_str());

    //-- Check response
    if (std::strcmp(response.toString().c_str(), "[ok]") == 0)
        return true;
    else
        return false;
}

bool rd::YarpNetworkManager::login()
{
    if ( ! started )
    {
        CD_WARNING("NetworkManager has not been started\n");
        if( ! start() )
        {
            CD_ERROR("NetworkManager could not be started for player %d\n", player.getId() );
            return false;
        }
    }

    //-- Start network system
    std::stringstream ss;
    ss << player.getId();

    //-- Send login message
    yarp::os::Bottle msgRdPlayer,res;
    msgRdPlayer.addVocab(VOCAB_RD_LOGIN);
    msgRdPlayer.addInt(player.getId());
    msgRdPlayer.addString(player.getName().c_str());
    msgRdPlayer.addInt(player.getTeamId());
    rpcClient.write(msgRdPlayer,res);
    CD_INFO("rdServer response from login: %s\n",res.toString().c_str());

    //-- Check response
    if (std::strcmp(res.toString().c_str(), "[ok]") == 0)
        return true;
    else
        return false;
}

bool rd::YarpNetworkManager::logout()
{
    if (!started)
    {
        CD_ERROR("NetworkManager has not been started\n");
        return false;
    }

    CD_INFO("Logout...\n");
    yarp::os::Bottle msgRdPlayer,res;
    msgRdPlayer.addVocab(VOCAB_RD_LOGOUT);
    msgRdPlayer.addInt(player.getId());
    rpcClient.write(msgRdPlayer,res);
    CD_INFO("rdServer response from logout: %s\n",res.toString().c_str());

    //-- Check response
    if (std::strcmp(res.toString().c_str(), "[ok]") == 0)
    {
        CD_SUCCESS("Logout ok\n");
        return true;
    }
    else
    {
        CD_ERROR("Logout failed\n");
        return false;
    }
}

bool rd::YarpNetworkManager::keepAlive()
{
    if (!started)
    {
        CD_ERROR("NetworkManager has not been started\n");
        return false;
    }

    CD_INFO("Keep alive...\n");
    yarp::os::Bottle msgRdPlayer,res;
    msgRdPlayer.addVocab(VOCAB_RD_KEEPALIVE);
    msgRdPlayer.addInt(player.getId());
    rpcClient.write(msgRdPlayer,res);

    //-- Check response
    if (std::strcmp(res.toString().c_str(), "[ok]") == 0)
    {
        return true;
    }
    else
    {
        CD_ERROR("Keep alive failed\n");
        return false;
    }
}
<commit_msg>astyle<commit_after>// Authors: see AUTHORS.md at project root.
// CopyPolicy: released under the terms of the LGPLv2.1, see LICENSE at project root.
// URL: https://github.com/asrob-uc3m/robotDevastation

#include "YarpNetworkManager.hpp"

#include <sstream>
#include <cstring> // strcmp()

#include <yarp/os/Network.h>

#include <ColorDebug.hpp>

#include "Vocabs.hpp"

//-- Initialize static members
rd::YarpNetworkManager * rd::YarpNetworkManager::uniqueInstance = NULL;
const std::string rd::YarpNetworkManager::id = "YARP";
const int rd::YarpNetworkManager::KEEPALIVE_RATE_MS = 1000;

bool rd::YarpNetworkManager::RegisterManager()
{
    if (uniqueInstance == NULL)
    {
        uniqueInstance = new YarpNetworkManager();
    }

    return Register( uniqueInstance, id);
}

rd::YarpNetworkManager::YarpNetworkManager() : RateThread(KEEPALIVE_RATE_MS)
{
    started = false;
}

void rd::YarpNetworkManager::run()
{
    keepAlive();
}

rd::YarpNetworkManager::~YarpNetworkManager()
{
    uniqueInstance = NULL;
}

bool rd::YarpNetworkManager::start()
{
    if (player.getId() == -1)
    {
        CD_ERROR("NetworkManager not initialized, player id not set\n");
        return false;
    }

    if (started)
    {
        CD_ERROR("NetworkManager already started\n");
        return false;
    }

    yarp::os::Network::initMinimum();

    if ( ! yarp::os::Network::checkNetwork() )
    {
        CD_INFO_NO_HEADER("Checking for yarp network... ");
        CD_ERROR_NO_HEADER("[fail]\n");
        CD_INFO_NO_HEADER("Found no yarp network to connect to rdServer (try running \"yarpserver &\"), bye!\n");
        return false;
    }

    //-- Open the rpcClient port with this player's id
    std::ostringstream rpc_str;
    rpc_str << "/robotDevastation/";
    rpc_str << player.getId();
    rpc_str << "/rdServer/rpc:c";
    if( ! rpcClient.open( rpc_str.str() ) )
    {
        CD_ERROR("Could not open '%s'. Bye!\n",rpc_str.str().c_str());
        return false;
    }

    //-- Open the callback port with this player's id
    std::ostringstream callback_str;
    callback_str << "/robotDevastation/";
    callback_str << player.getId();
    callback_str << "/rdServer/info:i";
    if( ! callbackPort.open( callback_str.str() ) )
    {
        CD_ERROR("Could not open '%s'. Bye!\n",callback_str.str().c_str());
        return false;
    }

    //-- Connect robotDevastation RpcClient to rdServer RpcServer
    std::string rdServerRpcS("/rdServer/rpc:s");
    if( ! yarp::os::Network::connect( rpc_str.str() , rdServerRpcS ) )
    {
        CD_INFO_NO_HEADER("Checking for rdServer ports... ");
        CD_ERROR_NO_HEADER("[fail]\n");
        CD_INFO_NO_HEADER("Could not connect to rdServer '%s' port (try running \"rdServer &\"), bye!\n",rdServerRpcS.c_str());
        return false;
    }

    //-- Connect from rdServer info to robotDevastation callbackPort
    std::string rdServerInfoO("/rdServer/info:o");
    if ( ! yarp::os::Network::connect( rdServerInfoO, callback_str.str() ))
    {
        CD_INFO_NO_HEADER("Checking for rdServer ports... ");
        CD_ERROR_NO_HEADER("[fail]\n");
        CD_INFO_NO_HEADER("Could not connect from rdServer '%s' port (try running \"rdServer &\"), bye!\n",rdServerInfoO.c_str());
        return false;
    }
    CD_INFO_NO_HEADER("Checking for rdServer ports... ");
    CD_SUCCESS_NO_HEADER("[ok]\n");

    callbackPort.useCallback(*this);

    RateThread::start();

    started = true;
    return true;
}

void rd::YarpNetworkManager::onRead(yarp::os::Bottle &b)
{
    //CD_INFO("Got %s\n", b.toString().c_str());
    if ((b.get(0).asString() == "players")||(b.get(0).asVocab() == VOCAB_RD_PLAYERS)) {  // players //
        //CD_INFO("Number of players: %d\n",b.size()-1);  // -1 because of vocab.
        std::vector< Player > players;
        for (int i = 1; i < b.size(); i++)
        {
            Player rdPlayer(b.get(i).asList()->get(0).asInt(),
                              b.get(i).asList()->get(1).asString().c_str(),
                              b.get(i).asList()->get(2).asInt(),
                              b.get(i).asList()->get(3).asInt(),
                              b.get(i).asList()->get(4).asInt(),
                              b.get(i).asList()->get(5).asInt()
                              );
            players.push_back(rdPlayer);
        }

        //-- Notify listeners
        for (std::vector<NetworkEventListener *>::iterator it = listeners.begin(); it != listeners.end(); ++it)
        {
            (*it)->onDataArrived(players);
        }
    }
    else
    {
        CD_ERROR("What?\n");
    }

}

bool rd::YarpNetworkManager::stop()
{
    if (!started)
    {
        CD_ERROR("Already stopped\n");
        return false;
    }

    RateThread::askToStop();

    rpcClient.close();

    callbackPort.disableCallback();
    callbackPort.interrupt();
    callbackPort.close();

    yarp::os::NetworkBase::finiMinimum();

    started = false;
    return true;
}

bool rd::YarpNetworkManager::isStopped() const
{
    return ! started;
}

bool rd::YarpNetworkManager::configure(const std::string & parameter, const Player & value)
{
    if (parameter.compare("player") == 0)
    {
        player = value;
        return true;
    }

    return NetworkManager::configure(parameter, value);
}

bool rd::YarpNetworkManager::sendPlayerHit(const Player & player, int damage)
{
    if ( ! started )
    {
        CD_ERROR("NetworkManager has not been started\n");
        return false;
    }

    //-- Send a message to the server with the player Id and the damage done:
    yarp::os::Bottle msg_player_hit, response;
    msg_player_hit.addVocab(VOCAB_RD_HIT);
    msg_player_hit.addInt(player.getId());
    msg_player_hit.addInt(damage);
    rpcClient.write(msg_player_hit,response);
    CD_INFO("rdServer response from hit: %s\n",response.toString().c_str());

    //-- Check response
    if (std::strcmp(response.toString().c_str(), "[ok]") == 0)
        return true;
    else
        return false;
}

bool rd::YarpNetworkManager::login()
{
    if ( ! started )
    {
        CD_WARNING("NetworkManager has not been started\n");
        if( ! start() )
        {
            CD_ERROR("NetworkManager could not be started for player %d\n", player.getId() );
            return false;
        }
    }

    //-- Start network system
    std::stringstream ss;
    ss << player.getId();

    //-- Send login message
    yarp::os::Bottle msgRdPlayer,res;
    msgRdPlayer.addVocab(VOCAB_RD_LOGIN);
    msgRdPlayer.addInt(player.getId());
    msgRdPlayer.addString(player.getName().c_str());
    msgRdPlayer.addInt(player.getTeamId());
    rpcClient.write(msgRdPlayer,res);
    CD_INFO("rdServer response from login: %s\n",res.toString().c_str());

    //-- Check response
    if (std::strcmp(res.toString().c_str(), "[ok]") == 0)
        return true;
    else
        return false;
}

bool rd::YarpNetworkManager::logout()
{
    if (!started)
    {
        CD_ERROR("NetworkManager has not been started\n");
        return false;
    }

    CD_INFO("Logout...\n");
    yarp::os::Bottle msgRdPlayer,res;
    msgRdPlayer.addVocab(VOCAB_RD_LOGOUT);
    msgRdPlayer.addInt(player.getId());
    rpcClient.write(msgRdPlayer,res);
    CD_INFO("rdServer response from logout: %s\n",res.toString().c_str());

    //-- Check response
    if (std::strcmp(res.toString().c_str(), "[ok]") == 0)
    {
        CD_SUCCESS("Logout ok\n");
        return true;
    }
    else
    {
        CD_ERROR("Logout failed\n");
        return false;
    }
}

bool rd::YarpNetworkManager::keepAlive()
{
    if (!started)
    {
        CD_ERROR("NetworkManager has not been started\n");
        return false;
    }

    CD_INFO("Keep alive...\n");
    yarp::os::Bottle msgRdPlayer,res;
    msgRdPlayer.addVocab(VOCAB_RD_KEEPALIVE);
    msgRdPlayer.addInt(player.getId());
    rpcClient.write(msgRdPlayer,res);

    //-- Check response
    if (std::strcmp(res.toString().c_str(), "[ok]") == 0)
    {
        return true;
    }
    else
    {
        CD_ERROR("Keep alive failed\n");
        return false;
    }
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2017. The YARA Authors. All Rights Reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <stdint.h>
#include <stddef.h>

#include <yara.h>

extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
{
   yr_initialize();
  return 0;
}

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
  YR_COMPILER* compiler;

  char* buffer = (char*) malloc(size + 1);

  if (!buffer)
    return 1;

  strlcpy(buffer, data, size + 1);

  if (yr_compiler_create(&compiler) != ERROR_SUCCESS)
    return 1;

  if (yr_compiler_add_string(compiler, buffer, NULL) == 0)
  {
    if (yr_compiler_get_rules(compiler, &rules) != ERROR_SUCCESS)
      return 1;
  }

  yr_compiler_destroy(compiler);

  return 0;
}<commit_msg>Fix issues with rules fuzzer.<commit_after>/*
Copyright (c) 2017. The YARA Authors. All Rights Reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <stdint.h>
#include <stddef.h>

#include <yara.h>

extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
{
   yr_initialize();
  return 0;
}

extern "C" int LLVMFuzzerTestOneInput(const char *data, size_t size)
{
  YR_RULES* rules;
  YR_COMPILER* compiler;

  char* buffer = (char*) malloc(size + 1);

  if (!buffer)
    return 1;

  strlcpy(buffer, data, size + 1);

  if (yr_compiler_create(&compiler) != ERROR_SUCCESS)
    return 1;

  if (yr_compiler_add_string(compiler, (const char*) buffer, NULL) == 0)
  {
    if (yr_compiler_get_rules(compiler, &rules) != ERROR_SUCCESS)
      return 1;
  }

  yr_compiler_destroy(compiler);

  return 0;
}<|endoftext|>