|
|
|
@ -12,6 +12,13 @@
|
|
|
|
|
|
|
|
|
|
namespace llarp
|
|
|
|
|
{
|
|
|
|
|
const PathID_t OutboundMessageHandler::zeroID;
|
|
|
|
|
|
|
|
|
|
OutboundMessageHandler::OutboundMessageHandler(size_t maxQueueSize)
|
|
|
|
|
: outboundQueue(maxQueueSize), removedPaths(20), removedSomePaths(false)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
OutboundMessageHandler::QueueMessage(const RouterID &remote,
|
|
|
|
|
const ILinkMessage *msg,
|
|
|
|
@ -31,8 +38,9 @@ namespace llarp
|
|
|
|
|
|
|
|
|
|
std::copy_n(buf.base, buf.sz, message.first.data());
|
|
|
|
|
|
|
|
|
|
if(SendIfSession(remote, message))
|
|
|
|
|
if(_linkManager->HasSessionTo(remote))
|
|
|
|
|
{
|
|
|
|
|
QueueOutboundMessage(remote, std::move(message), msg->pathid);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -41,9 +49,13 @@ namespace llarp
|
|
|
|
|
util::Lock l(&_mutex);
|
|
|
|
|
|
|
|
|
|
// create queue for <remote> if it doesn't exist, and get iterator
|
|
|
|
|
auto itr_pair = outboundMessageQueue.emplace(remote, MessageQueue());
|
|
|
|
|
auto itr_pair =
|
|
|
|
|
pendingSessionMessageQueues.emplace(remote, MessageQueue());
|
|
|
|
|
|
|
|
|
|
itr_pair.first->second.push_back(std::move(message));
|
|
|
|
|
MessageQueueEntry entry;
|
|
|
|
|
entry.message = message;
|
|
|
|
|
entry.router = remote;
|
|
|
|
|
itr_pair.first->second.push(std::move(entry));
|
|
|
|
|
|
|
|
|
|
shouldCreateSession = itr_pair.second;
|
|
|
|
|
}
|
|
|
|
@ -56,6 +68,20 @@ namespace llarp
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
OutboundMessageHandler::Tick()
|
|
|
|
|
{
|
|
|
|
|
ProcessOutboundQueue();
|
|
|
|
|
RemoveEmptyPathQueues();
|
|
|
|
|
SendRoundRobin();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
OutboundMessageHandler::QueueRemoveEmptyPath(const PathID_t &pathid)
|
|
|
|
|
{
|
|
|
|
|
removedPaths.pushBack(pathid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: this
|
|
|
|
|
util::StatusObject
|
|
|
|
|
OutboundMessageHandler::ExtractStatus() const
|
|
|
|
@ -70,36 +96,38 @@ namespace llarp
|
|
|
|
|
{
|
|
|
|
|
_linkManager = linkManager;
|
|
|
|
|
_logic = logic;
|
|
|
|
|
|
|
|
|
|
outboundMessageQueues.emplace(zeroID, MessageQueue());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
OutboundMessageHandler::OnSessionEstablished(const RouterID &router)
|
|
|
|
|
{
|
|
|
|
|
FinalizeRequest(router, SendStatus::Success);
|
|
|
|
|
FinalizeSessionRequest(router, SendStatus::Success);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
OutboundMessageHandler::OnConnectTimeout(const RouterID &router)
|
|
|
|
|
{
|
|
|
|
|
FinalizeRequest(router, SendStatus::Timeout);
|
|
|
|
|
FinalizeSessionRequest(router, SendStatus::Timeout);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
OutboundMessageHandler::OnRouterNotFound(const RouterID &router)
|
|
|
|
|
{
|
|
|
|
|
FinalizeRequest(router, SendStatus::RouterNotFound);
|
|
|
|
|
FinalizeSessionRequest(router, SendStatus::RouterNotFound);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
OutboundMessageHandler::OnInvalidRouter(const RouterID &router)
|
|
|
|
|
{
|
|
|
|
|
FinalizeRequest(router, SendStatus::InvalidRouter);
|
|
|
|
|
FinalizeSessionRequest(router, SendStatus::InvalidRouter);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
OutboundMessageHandler::OnNoLink(const RouterID &router)
|
|
|
|
|
{
|
|
|
|
|
FinalizeRequest(router, SendStatus::NoLink);
|
|
|
|
|
FinalizeSessionRequest(router, SendStatus::NoLink);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
@ -190,34 +218,164 @@ namespace llarp
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
OutboundMessageHandler::QueueOutboundMessage(const RouterID &remote,
|
|
|
|
|
Message &&msg,
|
|
|
|
|
const PathID_t &pathid)
|
|
|
|
|
{
|
|
|
|
|
MessageQueueEntry entry;
|
|
|
|
|
entry.message = std::move(msg);
|
|
|
|
|
auto callback_copy = entry.message.second;
|
|
|
|
|
entry.router = remote;
|
|
|
|
|
entry.pathid = pathid;
|
|
|
|
|
if(outboundQueue.tryPushBack(std::move(entry))
|
|
|
|
|
!= llarp::thread::QueueReturn::Success)
|
|
|
|
|
{
|
|
|
|
|
DoCallback(callback_copy, SendStatus::Congestion);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
OutboundMessageHandler::FinalizeRequest(const RouterID &router,
|
|
|
|
|
SendStatus status)
|
|
|
|
|
OutboundMessageHandler::ProcessOutboundQueue()
|
|
|
|
|
{
|
|
|
|
|
while(not outboundQueue.empty())
|
|
|
|
|
{
|
|
|
|
|
// TODO: can we add util::thread::Queue::front() for move semantics here?
|
|
|
|
|
MessageQueueEntry entry = outboundQueue.popFront();
|
|
|
|
|
|
|
|
|
|
auto itr_pair =
|
|
|
|
|
outboundMessageQueues.emplace(entry.pathid, MessageQueue());
|
|
|
|
|
|
|
|
|
|
if(itr_pair.second && !entry.pathid.IsZero())
|
|
|
|
|
{
|
|
|
|
|
roundRobinOrder.push(entry.pathid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MessageQueue &path_queue = itr_pair.first->second;
|
|
|
|
|
if(path_queue.size() >= MAX_PATH_QUEUE_SIZE)
|
|
|
|
|
{
|
|
|
|
|
path_queue.pop(); // head drop
|
|
|
|
|
}
|
|
|
|
|
path_queue.push(std::move(entry));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
OutboundMessageHandler::RemoveEmptyPathQueues()
|
|
|
|
|
{
|
|
|
|
|
removedSomePaths = (not removedPaths.empty());
|
|
|
|
|
|
|
|
|
|
while(not removedPaths.empty())
|
|
|
|
|
{
|
|
|
|
|
auto itr = outboundMessageQueues.find(removedPaths.popFront());
|
|
|
|
|
if(itr != outboundMessageQueues.end())
|
|
|
|
|
{
|
|
|
|
|
outboundMessageQueues.erase(itr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
OutboundMessageHandler::SendRoundRobin()
|
|
|
|
|
{
|
|
|
|
|
// send non-routing messages first priority
|
|
|
|
|
auto &non_routing_mq = outboundMessageQueues[zeroID];
|
|
|
|
|
while(!non_routing_mq.empty())
|
|
|
|
|
{
|
|
|
|
|
MessageQueueEntry entry = std::move(non_routing_mq.front());
|
|
|
|
|
non_routing_mq.pop();
|
|
|
|
|
|
|
|
|
|
Send(entry.router, entry.message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t empty_count = 0;
|
|
|
|
|
size_t num_queues = roundRobinOrder.size();
|
|
|
|
|
|
|
|
|
|
if(removedSomePaths)
|
|
|
|
|
{
|
|
|
|
|
for(size_t i = 0; i < num_queues; i++)
|
|
|
|
|
{
|
|
|
|
|
PathID_t pathid = std::move(roundRobinOrder.front());
|
|
|
|
|
roundRobinOrder.pop();
|
|
|
|
|
|
|
|
|
|
if(outboundMessageQueues.find(pathid) != outboundMessageQueues.end())
|
|
|
|
|
{
|
|
|
|
|
roundRobinOrder.push(std::move(pathid));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
num_queues = roundRobinOrder.size();
|
|
|
|
|
size_t sent_count = 0;
|
|
|
|
|
if(num_queues == 0) // if no queues, return
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while(sent_count
|
|
|
|
|
< MAX_OUTBOUND_MESSAGES_PER_TICK) // TODO: better stop condition
|
|
|
|
|
{
|
|
|
|
|
PathID_t pathid = std::move(roundRobinOrder.front());
|
|
|
|
|
roundRobinOrder.pop();
|
|
|
|
|
|
|
|
|
|
auto &message_queue = outboundMessageQueues[pathid];
|
|
|
|
|
if(message_queue.size() > 0)
|
|
|
|
|
{
|
|
|
|
|
MessageQueueEntry entry = std::move(message_queue.front());
|
|
|
|
|
message_queue.pop();
|
|
|
|
|
|
|
|
|
|
Send(entry.router, entry.message);
|
|
|
|
|
empty_count = 0;
|
|
|
|
|
sent_count++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
empty_count++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
roundRobinOrder.push(std::move(pathid));
|
|
|
|
|
|
|
|
|
|
// if num_queues empty queues in a row, all queues empty.
|
|
|
|
|
if(empty_count == num_queues)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
OutboundMessageHandler::FinalizeSessionRequest(const RouterID &router,
|
|
|
|
|
SendStatus status)
|
|
|
|
|
{
|
|
|
|
|
MessageQueue movedMessages;
|
|
|
|
|
{
|
|
|
|
|
util::Lock l(&_mutex);
|
|
|
|
|
auto itr = outboundMessageQueue.find(router);
|
|
|
|
|
auto itr = pendingSessionMessageQueues.find(router);
|
|
|
|
|
|
|
|
|
|
if(itr == outboundMessageQueue.end())
|
|
|
|
|
if(itr == pendingSessionMessageQueues.end())
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
movedMessages.splice(movedMessages.begin(), itr->second);
|
|
|
|
|
movedMessages.swap(itr->second);
|
|
|
|
|
|
|
|
|
|
outboundMessageQueue.erase(itr);
|
|
|
|
|
pendingSessionMessageQueues.erase(itr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(const auto &msg : movedMessages)
|
|
|
|
|
while(!movedMessages.empty())
|
|
|
|
|
{
|
|
|
|
|
MessageQueueEntry entry = std::move(movedMessages.front());
|
|
|
|
|
movedMessages.pop();
|
|
|
|
|
|
|
|
|
|
if(status == SendStatus::Success)
|
|
|
|
|
{
|
|
|
|
|
Send(router, msg);
|
|
|
|
|
Send(entry.router, entry.message);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
DoCallback(msg.second, status);
|
|
|
|
|
DoCallback(entry.message.second, status);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|