bool OTSocket::Send(const std::string & str_Reply) { OT_ASSERT_MSG(NULL != m_pSocket, "m_pSocket == NULL in OTSocket::Send()"); OT_ASSERT_MSG(NULL != m_pContext, "m_pContext == NULL in OTSocket::Send()"); OT_ASSERT_MSG(str_Reply.size() > 0, "str_Reply.size() > 0"); // ----------------------------------- const long lLatencySendMilliSec = OTLog::GetLatencySendMs(); const long lLatencySendMicroSec = lLatencySendMilliSec*1000; // Microsecond is 1000 times smaller than millisecond. // Convert the std::string (reply) into a ZMQ message zmq::message_t reply (str_Reply.length()); memcpy((void *) reply.data(), str_Reply.c_str(), str_Reply.length()); // ----------------------------------- bool bSuccessSending = false; if (OTLog::IsBlocking()) { bSuccessSending = m_pSocket->send(reply); // Blocking. } else // not blocking { int nSendTries = OTLog::GetLatencySendNoTries(); long lDoubling = lLatencySendMicroSec; bool bKeepTrying = true; while (bKeepTrying && (nSendTries > 0)) { zmq::pollitem_t items [] = { { (*m_pSocket), 0, ZMQ_POLLOUT, 0 } }; const int nPoll = zmq::poll(&items[0], 1, lDoubling); // ZMQ_POLLOUT, 1 item, timeout (microseconds in ZMQ 2.1; changes to milliseconds in 3.0) lDoubling *= 2; if (items[0].revents & ZMQ_POLLOUT) { bSuccessSending = m_pSocket->send(reply, ZMQ_NOBLOCK); // <=========== SEND =============== 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; } } return bSuccessSending; }
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; }