Example #1
0
// FIXME: This leaks RPCSub objects for JSON-RPC.  Shouldn't matter for anyone
// sane.
Json::Value doUnsubscribe (RPC::Context& context)
{

    InfoSub::pointer ispSub;
    Json::Value jvResult (Json::objectValue);

    if (!context.infoSub && !context.params.isMember (jss::url))
    {
        // Must be a JSON-RPC call.
        return rpcError (rpcINVALID_PARAMS);
    }

    if (context.params.isMember (jss::url))
    {
        if (context.role != Role::ADMIN)
            return rpcError (rpcNO_PERMISSION);

        std::string strUrl  = context.params[jss::url].asString ();
        ispSub  = context.netOps.findRpcSub (strUrl);

        if (!ispSub)
            return jvResult;
    }
    else
    {
        ispSub  = context.infoSub;
    }

    if (context.params.isMember (jss::streams))
    {
        for (auto& it: context.params[jss::streams])
        {
            if (it.isString ())
            {
                std::string streamName = it.asString ();

                if (streamName == "server")
                    context.netOps.unsubServer (ispSub->getSeq ());

                else if (streamName == "ledger")
                    context.netOps.unsubLedger (ispSub->getSeq ());

                else if (streamName == "transactions")
                    context.netOps.unsubTransactions (ispSub->getSeq ());

                else if (streamName == "transactions_proposed"
                         || streamName == "rt_transactions") // DEPRECATED
                    context.netOps.unsubRTTransactions (ispSub->getSeq ());

                else
                    jvResult[jss::error] = "Unknown stream: " + streamName;
            }
            else
            {
                jvResult[jss::error]   = "malformedSteam";
            }
        }
    }

    if (context.params.isMember (jss::accounts_proposed)
        || context.params.isMember (jss::rt_accounts))
    {
        auto accounts  = RPC::parseAccountIds (
                    context.params.isMember (jss::accounts_proposed)
                    ? context.params[jss::accounts_proposed]
                    : context.params[jss::rt_accounts]); // DEPRECATED

        if (accounts.empty ())
            jvResult[jss::error]   = "malformedAccount";
        else
            context.netOps.unsubAccount (ispSub, accounts, true);
    }

    if (context.params.isMember (jss::accounts))
    {
        auto accounts  = RPC::parseAccountIds (context.params[jss::accounts]);

        if (accounts.empty ())
            jvResult[jss::error]   = "malformedAccount";
        else
            context.netOps.unsubAccount (ispSub, accounts, false);
    }

    if (!context.params.isMember (jss::books))
    {
    }
    else if (!context.params[jss::books].isArray ())
    {
        return rpcError (rpcINVALID_PARAMS);
    }
    else
    {
        for (auto& jv: context.params[jss::books])
        {
            if (!jv.isObject ()
                    || !jv.isMember (jss::taker_pays)
                    || !jv.isMember (jss::taker_gets)
                    || !jv[jss::taker_pays].isObject ()
                    || !jv[jss::taker_gets].isObject ())
                return rpcError (rpcINVALID_PARAMS);

            bool bBoth = (jv.isMember (jss::both) && jv[jss::both].asBool ()) ||
                    (jv.isMember (jss::both_sides) && jv[jss::both_sides].asBool ());
            // both_sides is deprecated.

            Json::Value taker_pays = jv[jss::taker_pays];
            Json::Value taker_gets = jv[jss::taker_gets];

            Book book;

            // Parse mandatory currency.
            if (!taker_pays.isMember (jss::currency)
                || !to_currency (
                    book.in.currency, taker_pays[jss::currency].asString ()))
            {
                WriteLog (lsINFO, RPCHandler) << "Bad taker_pays currency.";
                return rpcError (rpcSRC_CUR_MALFORMED);
            }
            // Parse optional issuer.
            else if (((taker_pays.isMember (jss::issuer))
                      && (!taker_pays[jss::issuer].isString ()
                          || !to_issuer (
                              book.in.account, taker_pays[jss::issuer].asString ())))
                     // Don't allow illegal issuers.
                     || !isConsistent (book.in)
                     || noAccount() == book.in.account)
            {
                WriteLog (lsINFO, RPCHandler) << "Bad taker_pays issuer.";

                return rpcError (rpcSRC_ISR_MALFORMED);
            }

            // Parse mandatory currency.
            if (!taker_gets.isMember (jss::currency)
                    || !to_currency (book.out.currency,
                                     taker_gets[jss::currency].asString ()))
            {
                WriteLog (lsINFO, RPCHandler) << "Bad taker_pays currency.";

                return rpcError (rpcSRC_CUR_MALFORMED);
            }
            // Parse optional issuer.
            else if (((taker_gets.isMember (jss::issuer))
                      && (!taker_gets[jss::issuer].isString ()
                          || !to_issuer (book.out.account,
                                         taker_gets[jss::issuer].asString ())))
                     // Don't allow illegal issuers.
                     || !isConsistent (book.out)
                     || noAccount() == book.out.account)
            {
                WriteLog (lsINFO, RPCHandler) << "Bad taker_gets issuer.";

                return rpcError (rpcDST_ISR_MALFORMED);
            }

            if (book.in == book.out)
            {
                WriteLog (lsINFO, RPCHandler)
                    << "taker_gets same as taker_pays.";
                return rpcError (rpcBAD_MARKET);
            }

            context.netOps.unsubBook (ispSub->getSeq (), book);

            if (bBoth)
                context.netOps.unsubBook (ispSub->getSeq (), book);
        }
    }

    return jvResult;
}
Example #2
0
void PathRequests::updateAll (Ledger::ref inLedger, CancelCallback shouldCancel)
{
    std::vector<PathRequest::wptr> requests;

    LoadEvent::autoptr event (getApp().getJobQueue().getLoadEventAP(jtPATH_FIND, "PathRequest::updateAll"));

    // Get the ledger and cache we should be using
    Ledger::pointer ledger = inLedger;
    RippleLineCache::pointer cache;
    {
        ScopedLockType sl (mLock);
        requests = mRequests;
        cache = getLineCache (ledger, true);
    }

    bool newRequests = getApp().getLedgerMaster().isNewPathRequest();
    bool mustBreak = false;

    mJournal.trace << "updateAll seq=" << ledger->getLedgerSeq() << ", " <<
                   requests.size() << " requests";
    int processed = 0, removed = 0;

    do
    {

        BOOST_FOREACH (PathRequest::wref wRequest, requests)
        {
            if (shouldCancel())
                break;

            bool remove = true;
            PathRequest::pointer pRequest = wRequest.lock ();

            if (pRequest)
            {
                if (!pRequest->needsUpdate (newRequests, ledger->getLedgerSeq ()))
                    remove = false;
                else
                {
                    InfoSub::pointer ipSub = pRequest->getSubscriber ();
                    if (ipSub)
                    {
                        ipSub->getConsumer ().charge (Resource::feePathFindUpdate);
                        if (!ipSub->getConsumer ().warn ())
                        {
                            Json::Value update = pRequest->doUpdate (cache, false);
                            pRequest->updateComplete ();
                            update["type"] = "path_find";
                            ipSub->send (update, false);
                            remove = false;
                            ++processed;
                        }
                    }
                }
            }

            if (remove)
            {
                PathRequest::pointer pRequest = wRequest.lock ();

                ScopedLockType sl (mLock);

                // Remove any dangling weak pointers or weak pointers that refer to this path request.
                std::vector<PathRequest::wptr>::iterator it = mRequests.begin();
                while (it != mRequests.end())
                {
                    PathRequest::pointer itRequest = it->lock ();
                    if (!itRequest || (itRequest == pRequest))
                    {
                        ++removed;
                        it = mRequests.erase (it);
                    }
                    else
                        ++it;
                }
            }

            mustBreak = !newRequests && getApp().getLedgerMaster().isNewPathRequest();
            if (mustBreak) // We weren't handling new requests and then there was a new request
                break;

        }

        if (mustBreak)
        {   // a new request came in while we were working
            newRequests = true;
        }
        else if (newRequests)
        {   // we only did new requests, so we always need a last pass
            newRequests = getApp().getLedgerMaster().isNewPathRequest();
        }
        else
        {   // check if there are any new requests, otherwise we are done
            newRequests = getApp().getLedgerMaster().isNewPathRequest();
            if (!newRequests) // We did a full pass and there are no new requests
                return;
        }

        {
            // Get the latest requests, cache, and ledger for next pass
            ScopedLockType sl (mLock);

            if (mRequests.empty())
                break;
            requests = mRequests;

            cache = getLineCache (ledger, false);
        }

    }
    while (!shouldCancel ());

    mJournal.debug << "updateAll complete " << processed << " process and " <<
                   removed << " removed";
}
Example #3
0
Json::Value doUnsubscribe (RPC::Context& context)
{

    InfoSub::pointer ispSub;
    Json::Value jvResult (Json::objectValue);
    bool removeUrl {false};

    if (! context.infoSub && ! context.params.isMember(jss::url))
    {
        // Must be a JSON-RPC call.
        return rpcError(rpcINVALID_PARAMS);
    }

    if (context.params.isMember(jss::url))
    {
        if (context.role != Role::ADMIN)
            return rpcError(rpcNO_PERMISSION);

        std::string strUrl = context.params[jss::url].asString ();
        ispSub = context.netOps.findRpcSub (strUrl);
        if (! ispSub)
            return jvResult;
        removeUrl = true;
    }
    else
    {
        ispSub = context.infoSub;
    }

    if (context.params.isMember (jss::streams))
    {
        if (! context.params[jss::streams].isArray ())
            return rpcError (rpcINVALID_PARAMS);

        for (auto& it: context.params[jss::streams])
        {
            if (! it.isString())
                return rpcError(rpcSTREAM_MALFORMED);

            std::string streamName = it.asString ();
            if (streamName == "server")
            {
                context.netOps.unsubServer (ispSub->getSeq ());
            }
            else if (streamName == "ledger")
            {
                context.netOps.unsubLedger (ispSub->getSeq ());
            }
            else if (streamName == "manifests")
            {
                context.netOps.unsubManifests (ispSub->getSeq ());
            }
            else if (streamName == "transactions")
            {
                context.netOps.unsubTransactions (ispSub->getSeq ());
            }
            else if (streamName == "transactions_proposed"
                || streamName == "rt_transactions") // DEPRECATED
            {
                context.netOps.unsubRTTransactions (ispSub->getSeq ());
            }
            else if (streamName == "validations")
            {
                context.netOps.unsubValidations (ispSub->getSeq ());
            }
            else if (streamName == "peer_status")
            {
                context.netOps.unsubPeerStatus (ispSub->getSeq ());
            }
            else
            {
                return rpcError(rpcSTREAM_MALFORMED);
            }
        }
    }

    auto accountsProposed = context.params.isMember(jss::accounts_proposed)
        ? jss::accounts_proposed : jss::rt_accounts;  // DEPRECATED
    if (context.params.isMember(accountsProposed))
    {
        if (! context.params[accountsProposed].isArray())
            return rpcError(rpcINVALID_PARAMS);

        auto ids = RPC::parseAccountIds(context.params[accountsProposed]);
        if (ids.empty())
            return rpcError(rpcACT_MALFORMED);
        context.netOps.unsubAccount(ispSub, ids, true);
    }

    if (context.params.isMember(jss::accounts))
    {
        if (! context.params[jss::accounts].isArray())
            return rpcError(rpcINVALID_PARAMS);

        auto ids = RPC::parseAccountIds(context.params[jss::accounts]);
        if (ids.empty())
            return rpcError(rpcACT_MALFORMED);
        context.netOps.unsubAccount(ispSub, ids, false);
    }

    if (context.params.isMember(jss::books))
    {
        if (! context.params[jss::books].isArray())
            return rpcError(rpcINVALID_PARAMS);

        for (auto& jv: context.params[jss::books])
        {
            if (! jv.isObject() ||
                ! jv.isMember(jss::taker_pays) ||
                ! jv.isMember(jss::taker_gets) ||
                ! jv[jss::taker_pays].isObject() ||
                ! jv[jss::taker_gets].isObject())
            {
                return rpcError(rpcINVALID_PARAMS);
            }

            Json::Value taker_pays = jv[jss::taker_pays];
            Json::Value taker_gets = jv[jss::taker_gets];

            Book book;

            // Parse mandatory currency.
            if (!taker_pays.isMember (jss::currency)
                || !to_currency (
                    book.in.currency, taker_pays[jss::currency].asString ()))
            {
                JLOG (context.j.info()) << "Bad taker_pays currency.";
                return rpcError (rpcSRC_CUR_MALFORMED);
            }
            // Parse optional issuer.
            else if (((taker_pays.isMember (jss::issuer))
                      && (!taker_pays[jss::issuer].isString ()
                          || !to_issuer (
                              book.in.account, taker_pays[jss::issuer].asString ())))
                     // Don't allow illegal issuers.
                     || !isConsistent (book.in)
                     || noAccount() == book.in.account)
            {
                JLOG (context.j.info()) << "Bad taker_pays issuer.";

                return rpcError (rpcSRC_ISR_MALFORMED);
            }

            // Parse mandatory currency.
            if (!taker_gets.isMember (jss::currency)
                    || !to_currency (book.out.currency,
                                     taker_gets[jss::currency].asString ()))
            {
                JLOG (context.j.info()) << "Bad taker_gets currency.";

                return rpcError (rpcDST_AMT_MALFORMED);
            }
            // Parse optional issuer.
            else if (((taker_gets.isMember (jss::issuer))
                      && (!taker_gets[jss::issuer].isString ()
                          || !to_issuer (book.out.account,
                                         taker_gets[jss::issuer].asString ())))
                     // Don't allow illegal issuers.
                     || !isConsistent (book.out)
                     || noAccount() == book.out.account)
            {
                JLOG (context.j.info()) << "Bad taker_gets issuer.";

                return rpcError (rpcDST_ISR_MALFORMED);
            }

            if (book.in == book.out)
            {
                JLOG (context.j.info())
                    << "taker_gets same as taker_pays.";
                return rpcError (rpcBAD_MARKET);
            }

            context.netOps.unsubBook (ispSub->getSeq (), book);

            // both_sides is deprecated.
            if ((jv.isMember(jss::both) && jv[jss::both].asBool()) ||
                (jv.isMember(jss::both_sides) && jv[jss::both_sides].asBool()))
            {
                context.netOps.unsubBook(ispSub->getSeq(), reversed(book));
            }
        }
    }

    if (removeUrl)
    {
        context.netOps.tryRemoveRpcSub(context.params[jss::url].asString ());
    }

    return jvResult;
}