/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /** * Copyright (c) 2017 Alexander Afanasyev * * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with this program. * If not, see . */ #include "arp-cache.hpp" #include "core/utils.hpp" #include "core/interface.hpp" #include "simple-router.hpp" #include #include namespace simple_router { ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // IMPLEMENT THIS METHOD void ArpCache::periodicCheckArpRequestsAndCacheEntries() { // printf("periodicCheckArpRequestsAndCacheEntries\n"); // FILL THIS IN std::vector> arpRequestToRemove; for (auto &request : m_arpRequests) { if (request->nTimesSent >= 5){ arpRequestToRemove.push_back(request); for (auto &pendingPacket: request->packets){ m_router.sendICMPt3NonExisting(pendingPacket, 3, 3); } } else{ request->nTimesSent++; m_router.sendArpRequest(request->ip); } } for (auto request : arpRequestToRemove){ m_arpRequests.remove(request); } std::vector> arpEntryToRemove; for (auto &entry : m_cacheEntries){ if (!entry->isValid){ arpEntryToRemove.push_back(entry); } } for (auto entry : arpEntryToRemove){ m_cacheEntries.remove(entry); } } std::shared_ptr ArpCache::queueRequestWithoutLock(uint32_t ip, const Buffer& packet, const std::string& iface) { auto request = std::find_if(m_arpRequests.begin(), m_arpRequests.end(), [ip] (const std::shared_ptr& request) { return (request->ip == ip); }); if (request == m_arpRequests.end()) { request = m_arpRequests.insert(m_arpRequests.end(), std::make_shared(ip)); } // Add the packet to the list of packets for this request (*request)->packets.push_back({packet, iface}); return *request; } std::shared_ptr ArpCache::lookupWithoutLock(uint32_t ip) { for (const auto& entry : m_cacheEntries) { if (entry->isValid && entry->ip == ip) { return entry; } } return nullptr; } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // You should not need to touch the rest of this code. ArpCache::ArpCache(SimpleRouter& router) : m_router(router) , m_shouldStop(false) , m_tickerThread(std::bind(&ArpCache::ticker, this)) { } ArpCache::~ArpCache() { m_shouldStop = true; m_tickerThread.join(); } std::shared_ptr ArpCache::lookup(uint32_t ip) { std::lock_guard lock(m_mutex); for (const auto& entry : m_cacheEntries) { if (entry->isValid && entry->ip == ip) { return entry; } } return nullptr; } std::shared_ptr ArpCache::queueRequest(uint32_t ip, const Buffer& packet, const std::string& iface) { std::lock_guard lock(m_mutex); auto request = std::find_if(m_arpRequests.begin(), m_arpRequests.end(), [ip] (const std::shared_ptr& request) { return (request->ip == ip); }); if (request == m_arpRequests.end()) { request = m_arpRequests.insert(m_arpRequests.end(), std::make_shared(ip)); } // Add the packet to the list of packets for this request (*request)->packets.push_back({packet, iface}); return *request; } void ArpCache::removeRequest(const std::shared_ptr& entry) { std::lock_guard lock(m_mutex); m_arpRequests.remove(entry); } std::shared_ptr ArpCache::insertArpEntry(const Buffer& mac, uint32_t ip) { std::lock_guard lock(m_mutex); auto entry = std::make_shared(); entry->mac = mac; entry->ip = ip; entry->timeAdded = steady_clock::now(); entry->isValid = true; m_cacheEntries.push_back(entry); auto request = std::find_if(m_arpRequests.begin(), m_arpRequests.end(), [ip] (const std::shared_ptr& request) { return (request->ip == ip); }); if (request != m_arpRequests.end()) { return *request; } else { return nullptr; } } void ArpCache::clear() { std::lock_guard lock(m_mutex); m_cacheEntries.clear(); m_arpRequests.clear(); } void ArpCache::ticker() { while (!m_shouldStop) { std::this_thread::sleep_for(std::chrono::seconds(1)); { std::lock_guard lock(m_mutex); auto now = steady_clock::now(); for (auto& entry : m_cacheEntries) { if (entry->isValid && (now - entry->timeAdded > SR_ARPCACHE_TO)) { entry->isValid = false; } } periodicCheckArpRequestsAndCacheEntries(); } } } std::ostream& operator<<(std::ostream& os, const ArpCache& cache) { std::lock_guard lock(cache.m_mutex); os << "\nMAC IP AGE VALID\n" << "-----------------------------------------------------------\n"; auto now = steady_clock::now(); for (const auto& entry : cache.m_cacheEntries) { os << macToString(entry->mac) << " " << ipToString(entry->ip) << " " << std::chrono::duration_cast((now - entry->timeAdded)).count() << " seconds " << entry->isValid << "\n"; } os << std::endl; return os; } } // namespace simple_router