Open-Transactions  0.93.0-ge03d287
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
MessageProcessor.cpp
Go to the documentation of this file.
1 /************************************************************
2  *
3  * MessageProcessor.cpp
4  *
5  */
6 
7 /************************************************************
8  -----BEGIN PGP SIGNED MESSAGE-----
9  Hash: SHA1
10 
11  * OPEN TRANSACTIONS
12  *
13  * Financial Cryptography and Digital Cash
14  * Library, Protocol, API, Server, CLI, GUI
15  *
16  * -- Anonymous Numbered Accounts.
17  * -- Untraceable Digital Cash.
18  * -- Triple-Signed Receipts.
19  * -- Cheques, Vouchers, Transfers, Inboxes.
20  * -- Basket Currencies, Markets, Payment Plans.
21  * -- Signed, XML, Ricardian-style Contracts.
22  * -- Scripted smart contracts.
23  *
24  * Copyright (C) 2010-2013 by "Fellow Traveler" (A pseudonym)
25  *
26  * EMAIL:
28  *
29  * BITCOIN: 1NtTPVVjDsUfDWybS4BwvHpG2pdS9RnYyQ
30  *
31  * KEY FINGERPRINT (PGP Key in license file):
32  * 9DD5 90EB 9292 4B48 0484 7910 0308 00ED F951 BB8E
33  *
34  * OFFICIAL PROJECT WIKI(s):
35  * https://github.com/FellowTraveler/Moneychanger
36  * https://github.com/FellowTraveler/Open-Transactions/wiki
37  *
38  * WEBSITE:
39  * http://www.OpenTransactions.org/
40  *
41  * Components and licensing:
42  * -- Moneychanger..A Java client GUI.....LICENSE:.....GPLv3
43  * -- otlib.........A class library.......LICENSE:...LAGPLv3
44  * -- otapi.........A client API..........LICENSE:...LAGPLv3
45  * -- opentxs/ot....Command-line client...LICENSE:...LAGPLv3
46  * -- otserver......Server Application....LICENSE:....AGPLv3
47  * Github.com/FellowTraveler/Open-Transactions/wiki/Components
48  *
49  * All of the above OT components were designed and written by
50  * Fellow Traveler, with the exception of Moneychanger, which
51  * was contracted out to Vicky C ([email protected]).
52  * The open-source community has since actively contributed.
53  *
54  * -----------------------------------------------------
55  *
56  * LICENSE:
57  * This program is free software: you can redistribute it
58  * and/or modify it under the terms of the GNU Affero
59  * General Public License as published by the Free Software
60  * Foundation, either version 3 of the License, or (at your
61  * option) any later version.
62  *
63  * ADDITIONAL PERMISSION under the GNU Affero GPL version 3
64  * section 7: (This paragraph applies only to the LAGPLv3
65  * components listed above.) If you modify this Program, or
66  * any covered work, by linking or combining it with other
67  * code, such other code is not for that reason alone subject
68  * to any of the requirements of the GNU Affero GPL version 3.
69  * (==> This means if you are only using the OT API, then you
70  * don't have to open-source your code--only your changes to
71  * Open-Transactions itself must be open source. Similar to
72  * LGPLv3, except it applies to software-as-a-service, not
73  * just to distributing binaries.)
74  *
75  * Extra WAIVER for OpenSSL, Lucre, and all other libraries
76  * used by Open Transactions: This program is released under
77  * the AGPL with the additional exemption that compiling,
78  * linking, and/or using OpenSSL is allowed. The same is true
79  * for any other open source libraries included in this
80  * project: complete waiver from the AGPL is hereby granted to
81  * compile, link, and/or use them with Open-Transactions,
82  * according to their own terms, as long as the rest of the
83  * Open-Transactions terms remain respected, with regard to
84  * the Open-Transactions code itself.
85  *
86  * Lucre License:
87  * This code is also "dual-license", meaning that Ben Lau-
88  * rie's license must also be included and respected, since
89  * the code for Lucre is also included with Open Transactions.
90  * See Open-Transactions/src/otlib/lucre/LUCRE_LICENSE.txt
91  * The Laurie requirements are light, but if there is any
92  * problem with his license, simply remove the Lucre code.
93  * Although there are no other blind token algorithms in Open
94  * Transactions (yet. credlib is coming), the other functions
95  * will continue to operate.
96  * See Lucre on Github: https://github.com/benlaurie/lucre
97  * -----------------------------------------------------
98  * You should have received a copy of the GNU Affero General
99  * Public License along with this program. If not, see:
100  * http://www.gnu.org/licenses/
101  *
102  * If you would like to use this software outside of the free
103  * software license, please contact FellowTraveler.
104  * (Unfortunately many will run anonymously and untraceably,
105  * so who could really stop them?)
106  *
107  * DISCLAIMER:
108  * This program is distributed in the hope that it will be
109  * useful, but WITHOUT ANY WARRANTY; without even the implied
110  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
111  * PURPOSE. See the GNU Affero General Public License for
112  * more details.
113 
114  -----BEGIN PGP SIGNATURE-----
115  Version: GnuPG v1.4.9 (Darwin)
116 
117  iQIcBAEBAgAGBQJRSsfJAAoJEAMIAO35UbuOQT8P/RJbka8etf7wbxdHQNAY+2cC
118  vDf8J3X8VI+pwMqv6wgTVy17venMZJa4I4ikXD/MRyWV1XbTG0mBXk/7AZk7Rexk
119  KTvL/U1kWiez6+8XXLye+k2JNM6v7eej8xMrqEcO0ZArh/DsLoIn1y8p8qjBI7+m
120  aE7lhstDiD0z8mwRRLKFLN2IH5rAFaZZUvj5ERJaoYUKdn4c+RcQVei2YOl4T0FU
121  LWND3YLoH8naqJXkaOKEN4UfJINCwxhe5Ke9wyfLWLUO7NamRkWD2T7CJ0xocnD1
122  sjAzlVGNgaFDRflfIF4QhBx1Ddl6wwhJfw+d08bjqblSq8aXDkmFA7HeunSFKkdn
123  oIEOEgyj+veuOMRJC5pnBJ9vV+7qRdDKQWaCKotynt4sWJDGQ9kWGWm74SsNaduN
124  TPMyr9kNmGsfR69Q2Zq/FLcLX/j8ESxU+HYUB4vaARw2xEOu2xwDDv6jt0j3Vqsg
125  x7rWv4S/Eh18FDNDkVRChiNoOIilLYLL6c38uMf1pnItBuxP3uhgY6COm59kVaRh
126  nyGTYCDYD2TK+fI9o89F1297uDCwEJ62U0Q7iTDp5QuXCoxkPfv8/kX6lS6T3y9G
127  M9mqIoLbIQ1EDntFv7/t6fUTS2+46uCrdZWbQ5RjYXdrzjij02nDmJAm2BngnZvd
128  kamH0Y/n11lCvo1oQxM+
129  =uSzz
130  -----END PGP SIGNATURE-----
131  **************************************************************/
132 
133 #include "ServerSettings.hpp"
134 #include "ServerLoader.hpp"
135 #include "MessageProcessor.hpp"
136 #include "OTServer.hpp"
137 #include "ClientConnection.hpp"
138 #include <opentxs/core/OTLog.hpp>
140 #include <opentxs/core/OTString.hpp>
145 #include <opentxs/ext/OTSocket.hpp>
146 
147 namespace
148 {
149 
150 enum {
151  SERVER_DEFAULT_LATENCY_SEND_MS = 5000,
152  SERVER_DEFAULT_LATENCY_SEND_NO_TRIES = 2,
153  SERVER_DEFAULT_LATENCY_RECEIVE_MS = 5000,
154  SERVER_DEFAULT_LATENCY_RECEIVE_NO_TRIES = 2,
155  SERVER_DEFAULT_LATENCY_DELAY_AFTER = 50,
156  SERVER_DEFAULT_IS_BLOCKING = 0
157 };
158 
159 } // namespace
160 
161 namespace opentxs
162 {
163 
165  : server_(loader.getServer())
166  , socket_()
167 {
168  init(loader.getPort());
169 }
170 
171 void MessageProcessor::init(int port)
172 {
173  OTString configFolderPath = "";
174  if (!OTDataFolder::GetConfigFilePath(configFolderPath)) {
175  OT_FAIL;
176  }
177  OTSettings settings(configFolderPath);
178 
179  settings.Reset();
180  if (!settings.Load()) {
181  OT_FAIL;
182  }
183 
184  OTSocket::Defaults socketDefaults(
185  SERVER_DEFAULT_LATENCY_SEND_MS, SERVER_DEFAULT_LATENCY_SEND_NO_TRIES,
186  SERVER_DEFAULT_LATENCY_RECEIVE_MS,
187  SERVER_DEFAULT_LATENCY_RECEIVE_NO_TRIES,
188  SERVER_DEFAULT_LATENCY_DELAY_AFTER, SERVER_DEFAULT_IS_BLOCKING);
189 
190  if (!socket_.Init(socketDefaults, &settings)) {
191  OT_FAIL;
192  }
193 
194  if (!settings.Save()) {
195  OT_FAIL;
196  }
197  settings.Reset();
198 
199  if (!socket_.NewContext()) {
200  OT_FAIL;
201  }
202 
203  if (port == 0) {
204  OT_FAIL;
205  }
206  OTString bindPath;
207  bindPath.Format("%s%d", "tcp://*:", port);
208 
209  if (!socket_.Listen(bindPath)) {
210  OT_FAIL;
211  }
212 }
213 
215 {
216  for (;;) {
217  // =-=-=- HEARTBEAT -=-=-=
218  //
219  // The Server now processes certain things on a regular basis.
220  // ProcessCron is what gives it the opportunity to do that.
221  // All of the Cron Items (including market trades, payment plans, smart
222  // contracts...)
223  // they all have their hooks here...
224  //
225  // Internally this is smart enough to know how often to actually
226  // activate itself.
227  server_->ProcessCron();
228  // Most often it just returns doing nothing (waiting for its timer.)
229  // Wait for client http requests (and process replies out to them.)
230  // Number of requests to process per heartbeat:
231  // ServerSettings::GetHeartbeatNoRequests()
232  //
233  // Loop: process up to 10 client requests, then sleep for 1/10th second.
234  // That's a total of 100 requests per second. Can the computers handle
235  // it?
236  // Is it too much or too little? Todo: load testing.
237  //
238  // Then: check for shutdown flag.
239  //
240  // Then: go back to the top ("do") and repeat the loop.... process cron,
241  // process 10 client requests, sleep, check for shutdown, etc.
242 
243  Timer t;
244  t.start();
245  double startTick = t.getElapsedTimeInMilliSec();
246 
247  // PROCESS X NUMBER OF REQUESTS (THIS PULSE.)
248  //
249  // Theoretically the "number of requests" that we process EACH PULSE.
250  // (The timing code here is still pretty new, need to do some load
251  // testing.)
252  for (int i = 0; i < ServerSettings::GetHeartbeatNoRequests(); i++) {
253  OTString messageString;
254 
255  // With 100ms heartbeat, receive will try 100 ms, then 200 ms, then
256  // 400 ms, total of 700.
257  // That's about 15 Receive() calls every 10 seconds. Therefore if I
258  // want the ProcessCron()
259  // to trigger every 10 seconds, I need to set the cron interval to
260  // roll over every 15 heartbeats.
261  // Therefore I will be using a real Timer for Cron, instead of the
262  // damn intervals.
263  bool received = socket_.Receive(messageString);
264 
265  if (received) {
266  if (messageString.GetLength() <= 0) {
267  OTLog::Error("server main: Received a message, but of 0 "
268  "length or less. Weird. (Skipping it.)\n");
269  }
270  else {
271  std::string strMsg(messageString.Get());
272  std::string reply;
273  bool shouldDisconnect = processMessage(strMsg, reply);
274 
275  if (reply.length() <= 0 || shouldDisconnect) {
277  0, "server main: ERROR: Unfortunately, not every "
278  "client request is "
279  "legible or worthy of a server response. :-) "
280  "Msg:\n\n%s\n\n",
281  strMsg.c_str());
282 
283  socket_.Listen();
284  }
285  else {
286  bool successSending = socket_.Send(reply.c_str());
287 
288  if (!successSending) {
289  OTLog::vError("server main: Socket ERROR: failed "
290  "while trying to send reply "
291  "back to client! \n\n "
292  "MESSAGE:\n%s\n\nREPLY:\n%s\n\n",
293  strMsg.c_str(), reply.c_str());
294  }
295  }
296  }
297  }
298  }
299 
300  // IF the time we had available wasn't all used up -- if some of it is
301  // still available, then SLEEP until we reach the NEXT PULSE. (In
302  // practice, we will probably use TOO MUCH time, not too little--but
303  // then again OT isn't ALWAYS processing a message. There could be
304  // plenty of dead time in between...)
305  double endTick = t.getElapsedTimeInMilliSec();
306  int64_t elapsed = static_cast<int64_t>(endTick - startTick);
307 
309  int64_t ms = ServerSettings::GetHeartbeatMsBetweenBeats() - elapsed;
311  }
312 
313  if (server_->IsFlaggedForShutdown()) {
314  OTLog::Output(0, "opentxs server is shutting down gracefully.\n");
315  break;
316  }
317  }
318 }
319 
320 bool MessageProcessor::processMessage(const std::string& messageString,
321  std::string& reply)
322 {
323  if (messageString.size() < 1) return false;
324 
325  // First we grab the client's message
326  OTASCIIArmor ascMessage;
327  ascMessage.MemSet(messageString.data(), messageString.size());
328 
329  OTEnvelope envelope;
330  if (!envelope.SetAsciiArmoredData(ascMessage)) {
331  OTLog::vError("Error retrieving envelope.\n");
332  return true;
333  }
334 
335  // Now the base64 is decoded and the envelope is in binary form again.
336  OTLog::vOutput(2, "Successfully retrieved envelope from message.\n");
337 
338  // Decrypt the Envelope.
339  OTString envelopeContents;
340  if (!envelope.Open(server_->GetServerNym(), envelopeContents)) {
341  OTLog::vError("Unable to open envelope.\n");
342  return true;
343  }
344 
345  // All decrypted--now let's load the results into an OTMessage.
346  // No need to call message.ParseRawFile() after, since
347  // LoadContractFromString handles it.
348  OTMessage message;
349  if (!envelopeContents.Exists() ||
350  !message.LoadContractFromString(envelopeContents)) {
351  OTLog::vError("Error loading message from envelope "
352  "contents:\n\n%s\n\n",
353  envelopeContents.Get());
354  return true;
355  }
356 
357  OTMessage replyMessage;
358  replyMessage.m_strCommand.Format("@%s", message.m_strCommand.Get());
359  // UserID
360  replyMessage.m_strNymID = message.m_strNymID;
361  // ServerID, a hash of the server contract
362  replyMessage.m_strServerID = message.m_strServerID;
363  // The default reply. In fact this is probably superfluous
364  replyMessage.m_bSuccess = false;
365 
366  // By constructing this without a socket, I put it in ZMQ mode,
367  // instead of tcp/ssl.
368  ClientConnection client;
369 
370  OTPseudonym nym(message.m_strNymID);
371 
372  bool processedUserCmd = server_->userCommandProcessor_.ProcessUserCommand(
373  message, replyMessage, &client, &nym);
374 
375  // By optionally passing in &client, the client Nym's public
376  // key will be set on it whenever verification is complete. (So
377  // for the reply, I'll have the key and thus I'll be able to
378  // encrypt reply to the recipient.)
379  if (!processedUserCmd) {
380  OTString s1(message);
381 
382  OTLog::vOutput(0, "Unable to process user command: %s\n ********** "
383  "REQUEST:\n\n%s\n\n",
384  message.m_strCommand.Get(), s1.Get());
385 
386  // NOTE: normally you would even HAVE a true or false if
387  // we're in this block. ProcessUserCommand()
388  // is what tries to process a command and then sets false
389  // if/when it fails. Until that point, you
390  // wouldn't get any server reply. I'm now changing this
391  // slightly, so you still get a reply (defaulted
392  // to success==false.) That way if a client needs to re-sync
393  // his request number, he will get the false
394  // and therefore know to resync the # as his next move, vs
395  // being stuck with no server reply (and thus
396  // stuck with a bad socket.)
397  // We sign the reply here, but not in the else block, since
398  // it's already signed in cases where
399  // ProcessUserCommand() is a success, by the time that call
400  // returns.
401 
402  // Since the process call definitely failed, I'm
403  replyMessage.m_bSuccess = false;
404  // making sure this here is definitely set to
405  // false (even though it probably was already.)
406  replyMessage.SignContract(server_->GetServerNym());
407  replyMessage.SaveContract();
408 
409  OTString s2(replyMessage);
410 
411  OTLog::vOutput(0, " ********** RESPONSE:\n\n%s\n\n", s2.Get());
412  }
413  else {
414  // At this point the reply is ready to go, and client
415  // has the public key of the recipient...
416  OTLog::vOutput(1, "Successfully processed user command: %s.\n",
417  message.m_strCommand.Get());
418  }
419 
420  // IF ProcessUserCommand returned true, THEN we process the
421  // message for the recipient.
422  // ELSE IF ProcessUserCommand returned false, YET the PubKey
423  // DOES exist, THEN in this case also, we process the message
424  // for the recipient.
425  //
426  // if success + Nym's pub key exists here on server.
427  if (processedUserCmd || nym.Server_PubKeyExists()) {
428  // The transaction is now processed (or not), and the
429  // server's reply message is in replyMessage.
430  // Let's seal it up to the recipient's nym (in an envelope)
431  // and send back to the user...
432  OTEnvelope recipientEnvelope;
433 
434  bool sealed =
435  client.SealMessageForRecipient(replyMessage, recipientEnvelope);
436 
437  if (!sealed) {
438  OTLog::vOutput(0, "Unable to seal envelope. (No reply will be "
439  "sent.)\n");
440  return true;
441  }
442 
443  OTASCIIArmor ascReply;
444  if (!recipientEnvelope.GetAsciiArmoredData(ascReply)) {
446  0,
447  "Unable to GetAsciiArmoredData from sealed "
448  "envelope int oOTASCIIArmor object. (No reply envelope will be "
449  "sent.)\n");
450  return true;
451  }
452 
453  OTString output;
454  bool val = ascReply.Exists() &&
455  ascReply.WriteArmoredString(output, "ENVELOPE");
456 
457  if (!val || !output.Exists()) {
459  0, "Unable to WriteArmoredString from "
460  "OTASCIIArmor object into OTString object. (No reply "
461  "envelope will be sent.)\n");
462  return true;
463  }
464 
465  reply.assign(output.Get(), output.GetLength());
466  }
467  // ELSE we send the message in the CLEAR. (As an armored
468  // message, instead of as an armored envelope.)
469  else {
470  OTString replyString(replyMessage);
471 
472  if (!replyString.Exists()) {
473  OTLog::vOutput(0, "Failed trying to grab the reply "
474  "in OTString form. "
475  "(No reply message will be sent.)\n");
476  return true;
477  }
478 
479  OTASCIIArmor ascReply(replyString);
480  OTString output;
481  bool val =
482  ascReply.Exists() && ascReply.WriteArmoredString(output, "MESSAGE");
483 
484  if (!val || !output.Exists()) {
486  0, "Unable to WriteArmoredString from "
487  "OTASCIIArmor object into OTString object. (No reply "
488  "message will be sent.)\n");
489  return true;
490  }
491 
492  reply.assign(output.Get(), output.GetLength());
493  }
494 
495  return false;
496 }
497 
498 } // namespace opentxs
static EXPORT void vError(const char *szError,...)
Definition: OTLog.cpp:800
static EXPORT void Output(int32_t nVerbosity, const char *szOutput)
Definition: OTLog.cpp:710
Definition: Timer.hpp:31
EXPORT double getElapsedTimeInMilliSec()
Definition: Timer.cpp:111
static EXPORT bool GetConfigFilePath(OTString &strConfigFilePath)
bool IsFlaggedForShutdown() const
Definition: OTServer.cpp:350
EXPORT void start()
Definition: Timer.cpp:41
EXPORT uint32_t GetLength() const
Definition: OTString.cpp:1040
static int32_t GetHeartbeatNoRequests()
EXPORT bool SetAsciiArmoredData(const OTASCIIArmor &theArmoredText, bool bLineBreaks=true)
Definition: OTEnvelope.cpp:178
EXPORT bool Send(const OTASCIIArmor &ascEnvelope)
EXPORT bool Open(const OTPseudonym &theRecipient, OTString &theOutput, const OTPasswordData *pPWData=nullptr)
Definition: OTEnvelope.cpp:581
static EXPORT void Error(const char *szError)
Definition: OTLog.cpp:831
EXPORT bool Init(const Defaults &defaults)
Definition: OTSocket.cpp:202
const OTPseudonym & GetServerNym() const
Definition: OTServer.cpp:345
static int32_t GetHeartbeatMsBetweenBeats()
static EXPORT bool SleepMilliseconds(int64_t lMilliseconds)
Definition: OTLog.cpp:651
#define OT_FAIL
Definition: Assert.hpp:139
EXPORT const char * Get() const
Definition: OTString.cpp:1045
EXPORT bool Receive(OTString &strServerReply)
EXPORT MessageProcessor(ServerLoader &loader)
bool ProcessUserCommand(OTMessage &msgIn, OTMessage &msgOut, ClientConnection *connection, OTPseudonym *nym)
EXPORT bool MemSet(const char *mem, uint32_t size)
Definition: OTString.cpp:967
static EXPORT void vOutput(int32_t nVerbosity, const char *szOutput,...)
Definition: OTLog.cpp:768
EXPORT bool NewContext()