示例#1
0
// 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