// Envelope copied into payload to prepare for sending. bool OTPayload::SetEnvelope(const OTEnvelope & theEnvelope) { OTASCIIArmor theArmor; if (theEnvelope.GetAsciiArmoredData(theArmor)) { uint32_t lSize = theArmor.GetLength()+1; //+1 for the null terminater if (theArmor.GetLength()) { SetPayloadSize(lSize + 1); // +1 for the checksum byte. // Copy it in. memcpy((void *)GetPointer(), theArmor.Get(), lSize); // Add the checksum, success. AppendChecksum( (OT_BYTE*)GetPointer(), lSize ); return true; } } return false; }
void ProcessMessage_ZMQ(const std::string & str_Message, std::string & str_Reply) { OT_ASSERT(NULL != g_pServer); if (str_Message.size() < 1) return; // -------------------- // return value. std::string resultString = ""; // Whatever we put in this string is what will get returned. // First we grab the client's message OTASCIIArmor ascMessage; ascMessage.MemSet(str_Message.data(), str_Message.size()); // ------------------ // // OTPayload thePayload; // thePayload.SetPayloadSize(str_Message.size()); // memcpy((void*)thePayload.GetPayloadPointer(), str_Message.data(), str_Message.size()); // ---------------------------------------------------------------------- // OTLog::vError("Envelope: \n%s\n Size: %ld\n", ascMessage.Get(), ascMessage.GetLength()); OTMessage theMsg, theReply; // we'll need these in a sec... // OTEnvelope theEnvelope(ascMessage); // Now the base64 is decoded and unpacked, and the envelope is in binary form again. OTEnvelope theEnvelope; // Now the base64 is decoded and the envelope is in binary form again. if (theEnvelope.SetAsciiArmoredData(ascMessage)) { OTLog::Output(2, "Successfully retrieved envelope from ZMQ message...\n"); OTString strEnvelopeContents; // OTString strPubkeyPath("TESTPUBKEY.txt"); // g_pServer->GetServerNym().SavePublicKey(strPubkeyPath); // Decrypt the Envelope. if (theEnvelope.Open(g_pServer->GetServerNym(), strEnvelopeContents)) // now strEnvelopeContents contains the decoded message. { // All decrypted--now let's load the results into an OTMessage. // No need to call theMsg.ParseRawFile() after, since // LoadContractFromString handles it. // if (strEnvelopeContents.Exists() && theMsg.LoadContractFromString(strEnvelopeContents)) { // In case you want to see all the incoming messages... // OTLog::vOutput(0, "%s\n\n", strEnvelopeContents.Get()); // By constructing this without a socket, I put it in XmlRpc/http mode, instead of tcp/ssl. OTClientConnection theClient(*g_pServer); // By optionally passing in &theClient, the client Nym's public key will be // set on it whenever verification is complete. (So for the reply, I'll // have the key and thus I'll be able to encrypt reply to the recipient.) if (g_pServer->ProcessUserCommand(theMsg, theReply, &theClient)) { // At this point the reply is ready to go, and theClient has the public key of the recipient... OTLog::vOutput(1, "Successfully processed user command: %s.\n", theMsg.m_strCommand.Get()); // The transaction is now processed, and the server's reply message is in theReply. // Let's seal it up to the recipient's nym (in an envelope) and send back to the user... OTEnvelope theRecipientEnvelope; bool bSealed = theClient.SealMessageForRecipient(theReply, theRecipientEnvelope); if (bSealed) { // OTPayload theReplyPayload; // theReplyPayload.SetEnvelope(theRecipientEnvelope); // // resultString = ascReply.Get(); // resultString.assign(theReplyPayload.GetPayloadPointer(), theReplyPayload.GetPayloadSize()); OTASCIIArmor ascReply; if (theRecipientEnvelope.GetAsciiArmoredData(ascReply)); resultString.assign(ascReply.Get(), ascReply.GetLength()); } else OTLog::Output(0, "Unable to seal envelope in ProcessMessage_ZMQ.\n"); } else OTLog::Output(0, "Unable to process user command in ProcessMessage_ZMQ.\n"); } else OTLog::Error("Error loading message from envelope contents. ProcessMessage_ZMQ.\n"); } else OTLog::Error("Unable to open envelope. ProcessMessage_ZMQ.\n"); } else OTLog::Error("Error retrieving envelope from ProcessMessage_ZMQ.\n"); // ---------------------------------------------------------------------- str_Reply = resultString; }
bool OTSocket_ZMQ_4::Send(const OTASCIIArmor & ascEnvelope) { if (!m_bInitialized) { OT_FAIL; } if (0 >= ascEnvelope.GetLength()) { OTLog::vError("%s: Error: %s is zero length!\n", __FUNCTION__, "ascEnvelope"); OT_FAIL; } m_ascLastMsgSent.Set(ascEnvelope); // In case we need to re-send. if (!m_HasContext) { OT_FAIL; } if (NULL == m_pzmq->context_zmq) { OTLog::vError("%s: Error: %s must exist to Send!\n", __FUNCTION__, "m_pzmq->context_zmq"); OT_FAIL; } if (!m_bConnected && !m_bListening) return false; if (m_bConnected && m_bListening) return false; if (NULL == m_pzmq->socket_zmq) { OTLog::vError("%s: Error: %s must exist to Send!\n", __FUNCTION__, "m_pzmq->socket_zmq"); OT_FAIL; } // ----------------------------------- const int64_t lLatencySendMilliSec = m_lLatencySendMs; zmq::message_t zmq_message(ascEnvelope.GetLength()); memcpy((void*)zmq_message.data(), ascEnvelope.Get(), ascEnvelope.GetLength()); bool bSuccessSending = false; if (m_bIsBlocking) { try { bSuccessSending = m_pzmq->socket_zmq->send(zmq_message); // Blocking. } catch (std::exception& e) { OTLog::vError("%s: Exception Caught: %s \n", __FUNCTION__, e.what()); OT_FAIL; } } else // not blocking { int32_t nSendTries = m_nLatencySendNoTries; int64_t lDoubling = lLatencySendMilliSec; bool bKeepTrying = true; while (bKeepTrying && (nSendTries > 0)) { zmq::pollitem_t items[] = { { (*m_pzmq->socket_zmq), 0, ZMQ_POLLOUT, 0 } }; int nPoll = 0; try { nPoll = zmq::poll(&items[0], 1, static_cast<long>(lDoubling)); // ZMQ_POLLOUT, 1 item, timeout (milliseconds) } catch (std::exception& e) { OTLog::vError("%s: Exception Caught: %s \n", __FUNCTION__, e.what()); OT_FAIL; } lDoubling *= 2; if (items[0].revents & ZMQ_POLLOUT) { try { bSuccessSending = m_pzmq->socket_zmq->send(zmq_message, ZMQ_NOBLOCK); // <=========== SEND =============== } catch (std::exception& e) { OTLog::vError("%s: Exception Caught: %s \n", __FUNCTION__, e.what()); OT_FAIL; } OTLog::SleepMilliseconds(1); if (!bSuccessSending) { if (false == HandleSendingError()) bKeepTrying = false; } else break; // (Success -- we're done in this loop.) } else if ((-1) == nPoll) // error. { if (false == HandlePollingError()) bKeepTrying = false; } --nSendTries; } } /* Normally, we try to send... If the send fails, we wait X ms and then try again (Y times). BUT -- what if the failure was an errno==EAGAIN ? In that case, it's not a REAL failure, but rather, a "failure right now, try again in a sec." */ // *********************************** if (bSuccessSending) OTLog::SleepMilliseconds(m_lLatencyDelayAfter > 0 ? m_lLatencyDelayAfter : 1); return bSuccessSending; }
// true == YES, DISCONNECT m_pSocket, something must have gone wrong. // false == NO, do NOT disconnect m_pSocket, everything went wonderfully! // bool ProcessMessage_ZMQ(OTServer & theServer, const std::string & str_Message, std::string & str_Reply) { if (str_Message.size() < 1) return false; const char * szFunc = "ProcessMessage_ZMQ"; // -------------------- // return value. std::string resultString = ""; // Whatever we put in this string is what will get returned. // First we grab the client's message OTASCIIArmor ascMessage; ascMessage.MemSet(str_Message.data(), str_Message.size()); // ------------------ // // OTPayload thePayload; // thePayload.SetPayloadSize(str_Message.size()); // memcpy((void*)thePayload.GetPayloadPointer(), str_Message.data(), str_Message.size()); // ---------------------------------------------------------------------- // OTLog::vError("Envelope: \n%s\n Size: %ld\n", ascMessage.Get(), ascMessage.GetLength()); bool bReturnVal = false; // "false" == no, do NOT disconnect. No errors. ("True" means YES, DISCONNECT!) OTMessage theMsg, theReply; // we'll need these in a sec... // OTEnvelope theEnvelope(ascMessage); OTEnvelope theEnvelope; if (false == theEnvelope.SetAsciiArmoredData(ascMessage)) { OTLog::vError("%s: Error retrieving envelope.\n", szFunc); bReturnVal = true; // disconnect the socket! } else { // Now the base64 is decoded and the envelope is in binary form again. OTLog::vOutput(2, "%s: Successfully retrieved envelope from ZMQ message...\n", szFunc); OTString strEnvelopeContents; // OTString strPubkeyPath("TESTPUBKEY.txt"); // theServer.GetServerNym().SavePublicKey(strPubkeyPath); // Decrypt the Envelope. if (false == theEnvelope.Open(theServer.GetServerNym(), strEnvelopeContents)) // now strEnvelopeContents contains the decoded message. { OTLog::vError("%s: Unable to open envelope.\n", szFunc); bReturnVal = true; // disconnect the socket! } else { // All decrypted--now let's load the results into an OTMessage. // No need to call theMsg.ParseRawFile() after, since // LoadContractFromString handles it. // if (strEnvelopeContents.Exists() && theMsg.LoadContractFromString(strEnvelopeContents)) { theReply.m_strCommand.Format("@%s", theMsg.m_strCommand.Get()); theReply.m_strNymID = theMsg.m_strNymID; // UserID theReply.m_strServerID = theMsg.m_strServerID; // ServerID, a hash of the server contract. theReply.m_bSuccess = false; // The default reply. In fact this is probably superfluous. // In case you want to see all the incoming messages... // OTLog::vOutput(0, "%s\n\n", strEnvelopeContents.Get()); // By constructing this without a socket, I put it in ZMQ mode, instead of tcp/ssl. OTClientConnection theClient(theServer); // By optionally passing in &theClient, the client Nym's public key will be // set on it whenever verification is complete. (So for the reply, I'll // have the key and thus I'll be able to encrypt reply to the recipient.) if (false == theServer.ProcessUserCommand(theMsg, theReply, &theClient)) { const OTString s1(theMsg), s2(theReply); OTLog::vOutput(0, "%s: Unable to process user command.\n\n ********** " "REQUEST:\n\n%s\n\n ********** RESPONSE:\n\n%s\n\n", szFunc, s1.Get(), s2.Get()); // NOTE: normally you would even HAVE a true or false if we're in this block. ProcessUserCommand() // is what tries to process a command and then sets false if/when it fails. Until that point, you // wouldn't get any server reply. I'm now changing this slightly, so you still get a reply (defaulted // to success==false.) That way if a client needs to re-sync his request number, he will get the false // and therefore know to resync the # as his next move, vs being stuck with no server reply (and thus // stuck with a bad socket.) // We sign the reply here, but not in the else block, since it's already signed in cases where // ProcessUserCommand() is a success, by the time that call returns. theReply.m_bSuccess = false; // Since the process call definitely failed, I'm making sure this here is definitely set to false (even though it probably was already.) theReply.SignContract(theServer.GetServerNym()); theReply.SaveContract(); } else // At this point the reply is ready to go, and theClient has the public key of the recipient... OTLog::vOutput(1, "%s: Successfully processed user command: %s.\n", szFunc, theMsg.m_strCommand.Get()); // ------------------------------------------------- // The transaction is now processed (or not), and the server's reply message is in theReply. // Let's seal it up to the recipient's nym (in an envelope) and send back to the user... // OTEnvelope theRecipientEnvelope; bool bSealed = theClient.SealMessageForRecipient(theReply, theRecipientEnvelope); if (false == bSealed) { OTLog::vOutput(0, "%s: Unable to seal envelope. (No reply will be sent.)\n", szFunc); bReturnVal = true; // disconnect the socket! } else { // OTPayload theReplyPayload; // theReplyPayload.SetEnvelope(theRecipientEnvelope); // resultString = ascReply.Get(); // resultString.assign(theReplyPayload.GetPayloadPointer(), theReplyPayload.GetPayloadSize()); OTASCIIArmor ascReply; if (theRecipientEnvelope.GetAsciiArmoredData(ascReply)) resultString.assign(ascReply.Get(), ascReply.GetLength()); } } else { OTLog::vError("%s: Error loading message from envelope contents:\n\n%s\n\n", szFunc, strEnvelopeContents.Get()); bReturnVal = true; // disconnect the socket! } } } // ---------------------------------------------------------------------- str_Reply = resultString; return bReturnVal; } // ProcessMessage_ZMQ