#include #include #include #include #include namespace llarp { namespace service { SendContext::SendContext(const ServiceInfo& ident, const Introduction& intro, path::PathSet* send, Endpoint* ep) : remoteIdent(ident) , remoteIntro(intro) , m_PathSet(send) , m_DataHandler(ep) , m_Endpoint(ep) { createdAt = ep->Now(); currentConvoTag.Zero(); } bool SendContext::Send(const ProtocolFrame& msg, path::Path_ptr path) { auto transfer = std::make_shared< const routing::PathTransferMessage >( msg, remoteIntro.pathID); { util::Lock lock(&m_SendQueueMutex); m_SendQueue.emplace_back(transfer, path); } return true; } void SendContext::FlushUpstream() { auto r = m_Endpoint->Router(); util::Lock lock(&m_SendQueueMutex); for(const auto& item : m_SendQueue) { if(item.second->SendRoutingMessage(*item.first, r)) { lastGoodSend = r->Now(); } else LogError("Failed to send frame on path"); } m_SendQueue.clear(); } /// send on an established convo tag void SendContext::EncryptAndSendTo(const llarp_buffer_t& payload, ProtocolType t) { SharedSecret shared; ProtocolFrame f; f.N.Randomize(); f.T = currentConvoTag; f.S = ++sequenceNo; auto now = m_Endpoint->Now(); if(remoteIntro.ExpiresSoon(now)) { // shift intro if(MarkCurrentIntroBad(now)) { LogInfo("intro shifted"); } } auto path = m_PathSet->GetNewestPathByRouter(remoteIntro.router); if(!path) { LogError("cannot encrypt and send: no path for intro ", remoteIntro); return; } if(!m_DataHandler->GetCachedSessionKeyFor(f.T, shared)) { LogError("No cached session key"); return; } ProtocolMessage m; m_DataHandler->PutIntroFor(f.T, remoteIntro); m_DataHandler->PutReplyIntroFor(f.T, path->intro); m.proto = t; m.seqno = m_Endpoint->GetSeqNoForConvo(f.T); m.introReply = path->intro; f.F = m.introReply.pathID; m.sender = m_Endpoint->GetIdentity().pub; m.tag = f.T; m.PutBuffer(payload); if(!f.EncryptAndSign(m, shared, m_Endpoint->GetIdentity())) { LogError("failed to sign"); return; } Send(f, path); } void SendContext::AsyncEncryptAndSendTo(const llarp_buffer_t& data, ProtocolType protocol) { auto now = m_Endpoint->Now(); if(remoteIntro.ExpiresSoon(now)) { if(!ShiftIntroduction()) { LogWarn("no good path yet, your message may drop"); } } if(lastGoodSend) { EncryptAndSendTo(data, protocol); } else { AsyncGenIntro(data, protocol); } } } // namespace service } // namespace llarp