// // Copyright (C) 2015 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #include "shill/passive_link_monitor.h" #include #include #include "shill/arp_client.h" #include "shill/arp_packet.h" #include "shill/connection.h" #include "shill/event_dispatcher.h" #include "shill/logging.h" #include "shill/net/byte_string.h" using base::Bind; using base::Unretained; using std::string; namespace shill { namespace Logging { static auto kModuleLogScope = ScopeLogger::kLink; static string ObjectID(Connection* c) { return c->interface_name(); } } // static. const int PassiveLinkMonitor::kDefaultMonitorCycles = 40; const int PassiveLinkMonitor::kCyclePeriodMilliseconds = 25000; const int PassiveLinkMonitor::kMinArpRequestsPerCycle = 5; PassiveLinkMonitor::PassiveLinkMonitor(const ConnectionRefPtr& connection, EventDispatcher* dispatcher, const ResultCallback& result_callback) : connection_(connection), dispatcher_(dispatcher), // Connection is not provided when this is used as a mock for testing // purpose. arp_client_( new ArpClient(connection ? connection->interface_index() : 0)), result_callback_(result_callback), num_cycles_to_monitor_(kDefaultMonitorCycles), num_requests_received_(0), num_cycles_passed_(0) { } PassiveLinkMonitor::~PassiveLinkMonitor() { Stop(); } bool PassiveLinkMonitor::Start(int num_cycles) { SLOG(connection_.get(), 2) << "In " << __func__ << "."; Stop(); if (!StartArpClient()) { return false; } // Start the monitor cycle. monitor_cycle_timeout_callback_.Reset( Bind(&PassiveLinkMonitor::CycleTimeoutHandler, Unretained(this))); dispatcher_->PostDelayedTask(monitor_cycle_timeout_callback_.callback(), kCyclePeriodMilliseconds); num_cycles_to_monitor_ = num_cycles; return true; } void PassiveLinkMonitor::Stop() { SLOG(connection_.get(), 2) << "In " << __func__ << "."; StopArpClient(); num_requests_received_ = 0; num_cycles_passed_ = 0; monitor_cycle_timeout_callback_.Cancel(); monitor_completed_callback_.Cancel(); } bool PassiveLinkMonitor::StartArpClient() { if (!arp_client_->StartRequestListener()) { return false; } receive_request_handler_.reset( dispatcher_->CreateReadyHandler( arp_client_->socket(), IOHandler::kModeInput, Bind(&PassiveLinkMonitor::ReceiveRequest, Unretained(this)))); return true; } void PassiveLinkMonitor::StopArpClient() { arp_client_->Stop(); receive_request_handler_.reset(); } void PassiveLinkMonitor::ReceiveRequest(int fd) { SLOG(connection_.get(), 2) << "In " << __func__ << "."; ArpPacket packet; ByteString sender; if (!arp_client_->ReceivePacket(&packet, &sender)) { return; } if (packet.IsReply()) { SLOG(connection_.get(), 4) << "This is not a request packet. Ignoring."; return; } num_requests_received_++; // Stop ARP client if we receive enough requests for the current cycle. if (num_requests_received_ >= kMinArpRequestsPerCycle) { StopArpClient(); } } void PassiveLinkMonitor::CycleTimeoutHandler() { bool status = false; if (num_requests_received_ >= kMinArpRequestsPerCycle) { num_requests_received_ = 0; num_cycles_passed_++; if (num_cycles_passed_ < num_cycles_to_monitor_) { // Continue on with the next cycle. StartArpClient(); dispatcher_->PostDelayedTask(monitor_cycle_timeout_callback_.callback(), kCyclePeriodMilliseconds); return; } // Monitor completed. status = true; } // Post a task to perform cleanup and invoke result callback, since this // function is invoked from the callback that will be cancelled during // cleanup. monitor_completed_callback_.Reset( Bind(&PassiveLinkMonitor::MonitorCompleted, Unretained(this), status)); dispatcher_->PostTask(monitor_completed_callback_.callback()); } void PassiveLinkMonitor::MonitorCompleted(bool status) { // Stop the monitoring before invoking result callback, so that the ARP client // is stopped by the time result callback is invoked. Stop(); result_callback_.Run(status); } } // namespace shill