rippled
Unsubscribe.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012-2014 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/app/misc/NetworkOPs.h>
21 #include <ripple/basics/Log.h>
22 #include <ripple/net/RPCErr.h>
23 #include <ripple/protocol/ErrorCodes.h>
24 #include <ripple/protocol/jss.h>
25 #include <ripple/rpc/Context.h>
26 #include <ripple/rpc/Role.h>
27 #include <ripple/rpc/impl/RPCHelpers.h>
28 
29 namespace ripple {
30 
33 {
34  InfoSub::pointer ispSub;
36  bool removeUrl{false};
37 
38  if (!context.infoSub && !context.params.isMember(jss::url))
39  {
40  // Must be a JSON-RPC call.
42  }
43 
44  if (context.params.isMember(jss::url))
45  {
46  if (context.role != Role::ADMIN)
47  return rpcError(rpcNO_PERMISSION);
48 
49  std::string strUrl = context.params[jss::url].asString();
50  ispSub = context.netOps.findRpcSub(strUrl);
51  if (!ispSub)
52  return jvResult;
53  removeUrl = true;
54  }
55  else
56  {
57  ispSub = context.infoSub;
58  }
59 
60  if (context.params.isMember(jss::streams))
61  {
62  if (!context.params[jss::streams].isArray())
64 
65  for (auto& it : context.params[jss::streams])
66  {
67  if (!it.isString())
69 
70  std::string streamName = it.asString();
71  if (streamName == "server")
72  {
73  context.netOps.unsubServer(ispSub->getSeq());
74  }
75  else if (streamName == "ledger")
76  {
77  context.netOps.unsubLedger(ispSub->getSeq());
78  }
79  else if (streamName == "manifests")
80  {
81  context.netOps.unsubManifests(ispSub->getSeq());
82  }
83  else if (streamName == "transactions")
84  {
85  context.netOps.unsubTransactions(ispSub->getSeq());
86  }
87  else if (
88  streamName == "transactions_proposed" ||
89  streamName == "rt_transactions") // DEPRECATED
90  {
91  context.netOps.unsubRTTransactions(ispSub->getSeq());
92  }
93  else if (streamName == "validations")
94  {
95  context.netOps.unsubValidations(ispSub->getSeq());
96  }
97  else if (streamName == "peer_status")
98  {
99  context.netOps.unsubPeerStatus(ispSub->getSeq());
100  }
101  else if (streamName == "consensus")
102  {
103  context.netOps.unsubConsensus(ispSub->getSeq());
104  }
105  else
106  {
108  }
109  }
110  }
111 
112  auto accountsProposed = context.params.isMember(jss::accounts_proposed)
113  ? jss::accounts_proposed
114  : jss::rt_accounts; // DEPRECATED
115  if (context.params.isMember(accountsProposed))
116  {
117  if (!context.params[accountsProposed].isArray())
118  return rpcError(rpcINVALID_PARAMS);
119 
120  auto ids = RPC::parseAccountIds(context.params[accountsProposed]);
121  if (ids.empty())
122  return rpcError(rpcACT_MALFORMED);
123  context.netOps.unsubAccount(ispSub, ids, true);
124  }
125 
126  if (context.params.isMember(jss::accounts))
127  {
128  if (!context.params[jss::accounts].isArray())
129  return rpcError(rpcINVALID_PARAMS);
130 
131  auto ids = RPC::parseAccountIds(context.params[jss::accounts]);
132  if (ids.empty())
133  return rpcError(rpcACT_MALFORMED);
134  context.netOps.unsubAccount(ispSub, ids, false);
135  }
136 
137  if (context.params.isMember(jss::account_history_tx_stream))
138  {
139  auto const& req = context.params[jss::account_history_tx_stream];
140  if (!req.isMember(jss::account) || !req[jss::account].isString())
141  return rpcError(rpcINVALID_PARAMS);
142 
143  auto const id = parseBase58<AccountID>(req[jss::account].asString());
144  if (!id)
145  return rpcError(rpcINVALID_PARAMS);
146 
147  bool stopHistoryOnly = false;
148  if (req.isMember(jss::stop_history_tx_only))
149  {
150  if (!req[jss::stop_history_tx_only].isBool())
151  return rpcError(rpcINVALID_PARAMS);
152  stopHistoryOnly = req[jss::stop_history_tx_only].asBool();
153  }
154  context.netOps.unsubAccountHistory(ispSub, *id, stopHistoryOnly);
155 
156  JLOG(context.j.debug())
157  << "doUnsubscribe: account_history_tx_stream: " << toBase58(*id)
158  << " stopHistoryOnly=" << (stopHistoryOnly ? "true" : "false");
159  }
160 
161  if (context.params.isMember(jss::books))
162  {
163  if (!context.params[jss::books].isArray())
164  return rpcError(rpcINVALID_PARAMS);
165 
166  for (auto& jv : context.params[jss::books])
167  {
168  if (!jv.isObject() || !jv.isMember(jss::taker_pays) ||
169  !jv.isMember(jss::taker_gets) ||
170  !jv[jss::taker_pays].isObjectOrNull() ||
171  !jv[jss::taker_gets].isObjectOrNull())
172  {
173  return rpcError(rpcINVALID_PARAMS);
174  }
175 
176  Json::Value taker_pays = jv[jss::taker_pays];
177  Json::Value taker_gets = jv[jss::taker_gets];
178 
179  Book book;
180 
181  // Parse mandatory currency.
182  if (!taker_pays.isMember(jss::currency) ||
183  !to_currency(
184  book.in.currency, taker_pays[jss::currency].asString()))
185  {
186  JLOG(context.j.info()) << "Bad taker_pays currency.";
188  }
189  // Parse optional issuer.
190  else if (
191  ((taker_pays.isMember(jss::issuer)) &&
192  (!taker_pays[jss::issuer].isString() ||
193  !to_issuer(
194  book.in.account, taker_pays[jss::issuer].asString())))
195  // Don't allow illegal issuers.
196  || !isConsistent(book.in) || noAccount() == book.in.account)
197  {
198  JLOG(context.j.info()) << "Bad taker_pays issuer.";
199 
201  }
202 
203  // Parse mandatory currency.
204  if (!taker_gets.isMember(jss::currency) ||
205  !to_currency(
206  book.out.currency, taker_gets[jss::currency].asString()))
207  {
208  JLOG(context.j.info()) << "Bad taker_gets currency.";
209 
211  }
212  // Parse optional issuer.
213  else if (
214  ((taker_gets.isMember(jss::issuer)) &&
215  (!taker_gets[jss::issuer].isString() ||
216  !to_issuer(
217  book.out.account, taker_gets[jss::issuer].asString())))
218  // Don't allow illegal issuers.
219  || !isConsistent(book.out) || noAccount() == book.out.account)
220  {
221  JLOG(context.j.info()) << "Bad taker_gets issuer.";
222 
224  }
225 
226  if (book.in == book.out)
227  {
228  JLOG(context.j.info()) << "taker_gets same as taker_pays.";
229  return rpcError(rpcBAD_MARKET);
230  }
231 
232  context.netOps.unsubBook(ispSub->getSeq(), book);
233 
234  // both_sides is deprecated.
235  if ((jv.isMember(jss::both) && jv[jss::both].asBool()) ||
236  (jv.isMember(jss::both_sides) && jv[jss::both_sides].asBool()))
237  {
238  context.netOps.unsubBook(ispSub->getSeq(), reversed(book));
239  }
240  }
241  }
242 
243  if (removeUrl)
244  {
245  context.netOps.tryRemoveRpcSub(context.params[jss::url].asString());
246  }
247 
248  return jvResult;
249 }
250 
251 } // namespace ripple
ripple::to_currency
bool to_currency(Currency &currency, std::string const &code)
Tries to convert a string to a Currency, returns true on success.
Definition: UintTypes.cpp:80
ripple::RPC::Context::infoSub
InfoSub::pointer infoSub
Definition: Context.h:49
ripple::RPC::JsonContext
Definition: Context.h:53
ripple::rpcDST_AMT_MALFORMED
@ rpcDST_AMT_MALFORMED
Definition: ErrorCodes.h:106
std::string
STL class.
std::shared_ptr
STL class.
ripple::rpcINVALID_PARAMS
@ rpcINVALID_PARAMS
Definition: ErrorCodes.h:84
Json::Value::isString
bool isString() const
Definition: json_value.cpp:1009
ripple::rpcError
Json::Value rpcError(int iError)
Definition: RPCErr.cpp:29
ripple::isConsistent
bool isConsistent(Book const &book)
Definition: Book.cpp:25
ripple::InfoSub::Source::unsubTransactions
virtual bool unsubTransactions(std::uint64_t uListener)=0
ripple::Book::out
Issue out
Definition: Book.h:37
ripple::InfoSub::Source::unsubConsensus
virtual bool unsubConsensus(std::uint64_t uListener)=0
ripple::Issue::currency
Currency currency
Definition: Issue.h:37
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:104
ripple::RPC::Context::role
Role role
Definition: Context.h:47
ripple::InfoSub::Source::unsubValidations
virtual bool unsubValidations(std::uint64_t uListener)=0
ripple::RPC::Context::j
const beast::Journal j
Definition: Context.h:41
ripple::InfoSub::Source::findRpcSub
virtual pointer findRpcSub(std::string const &strUrl)=0
ripple::Role::ADMIN
@ ADMIN
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::InfoSub::Source::unsubBook
virtual bool unsubBook(std::uint64_t uListener, Book const &)=0
ripple::reversed
Book reversed(Book const &book)
Definition: Book.cpp:45
ripple::InfoSub::Source::unsubAccountHistory
virtual void unsubAccountHistory(ref ispListener, AccountID const &account, bool historyOnly)=0
unsubscribe an account's transactions
ripple::rpcSRC_ISR_MALFORMED
@ rpcSRC_ISR_MALFORMED
Definition: ErrorCodes.h:125
beast::Journal::info
Stream info() const
Definition: Journal.h:321
ripple::rpcSTREAM_MALFORMED
@ rpcSTREAM_MALFORMED
Definition: ErrorCodes.h:126
ripple::InfoSub::Source::unsubAccount
virtual void unsubAccount(ref isplistener, hash_set< AccountID > const &vnaAccountIDs, bool realTime)=0
Json::Value::isMember
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:932
ripple::rpcDST_ISR_MALFORMED
@ rpcDST_ISR_MALFORMED
Definition: ErrorCodes.h:108
ripple::InfoSub::Source::unsubRTTransactions
virtual bool unsubRTTransactions(std::uint64_t uListener)=0
ripple::InfoSub::Source::unsubPeerStatus
virtual bool unsubPeerStatus(std::uint64_t uListener)=0
ripple::RPC::Context::netOps
NetworkOPs & netOps
Definition: Context.h:44
Json::Value::isArray
bool isArray() const
Definition: json_value.cpp:1015
ripple::InfoSub::Source::unsubServer
virtual bool unsubServer(std::uint64_t uListener)=0
ripple::doUnsubscribe
Json::Value doUnsubscribe(RPC::JsonContext &)
Definition: Unsubscribe.cpp:32
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::rpcACT_MALFORMED
@ rpcACT_MALFORMED
Definition: ErrorCodes.h:90
ripple::InfoSub::Source::unsubManifests
virtual bool unsubManifests(std::uint64_t uListener)=0
ripple::rpcNO_PERMISSION
@ rpcNO_PERMISSION
Definition: ErrorCodes.h:53
ripple::InfoSub::Source::tryRemoveRpcSub
virtual bool tryRemoveRpcSub(std::string const &strUrl)=0
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
ripple::Book
Specifies an order book.
Definition: Book.h:33
ripple::rpcBAD_MARKET
@ rpcBAD_MARKET
Definition: ErrorCodes.h:97
ripple::rpcSRC_CUR_MALFORMED
@ rpcSRC_CUR_MALFORMED
Definition: ErrorCodes.h:124
ripple::RPC::parseAccountIds
hash_set< AccountID > parseAccountIds(Json::Value const &jvArray)
Definition: RPCHelpers.cpp:711
ripple::RPC::JsonContext::params
Json::Value params
Definition: Context.h:64
ripple::noAccount
AccountID const & noAccount()
A placeholder for empty accounts.
Definition: AccountID.cpp:175
ripple::Book::in
Issue in
Definition: Book.h:36
ripple::Issue::account
AccountID account
Definition: Issue.h:38
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::to_issuer
bool to_issuer(AccountID &, std::string const &)
Convert hex or base58 string to AccountID.
Definition: AccountID.cpp:182
ripple::InfoSub::Source::unsubLedger
virtual bool unsubLedger(std::uint64_t uListener)=0
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469