1 // 2 // Copyright (C) 2015 The Android Open Source Project 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 #include "shill/passive_link_monitor.h" 18 19 #include <string> 20 21 #include <base/bind.h> 22 23 #include "shill/arp_client.h" 24 #include "shill/arp_packet.h" 25 #include "shill/connection.h" 26 #include "shill/event_dispatcher.h" 27 #include "shill/logging.h" 28 #include "shill/net/byte_string.h" 29 30 using base::Bind; 31 using base::Unretained; 32 using std::string; 33 34 namespace shill { 35 36 namespace Logging { 37 static auto kModuleLogScope = ScopeLogger::kLink; 38 static string ObjectID(Connection* c) { return c->interface_name(); } 39 } 40 41 // static. 42 const int PassiveLinkMonitor::kDefaultMonitorCycles = 40; 43 const int PassiveLinkMonitor::kCyclePeriodMilliseconds = 25000; 44 const int PassiveLinkMonitor::kMinArpRequestsPerCycle = 5; 45 46 PassiveLinkMonitor::PassiveLinkMonitor(const ConnectionRefPtr& connection, 47 EventDispatcher* dispatcher, 48 const ResultCallback& result_callback) 49 : connection_(connection), 50 dispatcher_(dispatcher), 51 // Connection is not provided when this is used as a mock for testing 52 // purpose. 53 arp_client_( 54 new ArpClient(connection ? connection->interface_index() : 0)), 55 result_callback_(result_callback), 56 num_cycles_to_monitor_(kDefaultMonitorCycles), 57 num_requests_received_(0), 58 num_cycles_passed_(0) { 59 } 60 61 PassiveLinkMonitor::~PassiveLinkMonitor() { 62 Stop(); 63 } 64 65 bool PassiveLinkMonitor::Start(int num_cycles) { 66 SLOG(connection_.get(), 2) << "In " << __func__ << "."; 67 Stop(); 68 69 if (!StartArpClient()) { 70 return false; 71 } 72 // Start the monitor cycle. 73 monitor_cycle_timeout_callback_.Reset( 74 Bind(&PassiveLinkMonitor::CycleTimeoutHandler, Unretained(this))); 75 dispatcher_->PostDelayedTask(monitor_cycle_timeout_callback_.callback(), 76 kCyclePeriodMilliseconds); 77 num_cycles_to_monitor_ = num_cycles; 78 return true; 79 } 80 81 void PassiveLinkMonitor::Stop() { 82 SLOG(connection_.get(), 2) << "In " << __func__ << "."; 83 StopArpClient(); 84 num_requests_received_ = 0; 85 num_cycles_passed_ = 0; 86 monitor_cycle_timeout_callback_.Cancel(); 87 monitor_completed_callback_.Cancel(); 88 } 89 90 bool PassiveLinkMonitor::StartArpClient() { 91 if (!arp_client_->StartRequestListener()) { 92 return false; 93 } 94 receive_request_handler_.reset( 95 dispatcher_->CreateReadyHandler( 96 arp_client_->socket(), 97 IOHandler::kModeInput, 98 Bind(&PassiveLinkMonitor::ReceiveRequest, Unretained(this)))); 99 return true; 100 } 101 102 void PassiveLinkMonitor::StopArpClient() { 103 arp_client_->Stop(); 104 receive_request_handler_.reset(); 105 } 106 107 void PassiveLinkMonitor::ReceiveRequest(int fd) { 108 SLOG(connection_.get(), 2) << "In " << __func__ << "."; 109 ArpPacket packet; 110 ByteString sender; 111 112 if (!arp_client_->ReceivePacket(&packet, &sender)) { 113 return; 114 } 115 116 if (packet.IsReply()) { 117 SLOG(connection_.get(), 4) << "This is not a request packet. Ignoring."; 118 return; 119 } 120 121 num_requests_received_++; 122 // Stop ARP client if we receive enough requests for the current cycle. 123 if (num_requests_received_ >= kMinArpRequestsPerCycle) { 124 StopArpClient(); 125 } 126 } 127 128 void PassiveLinkMonitor::CycleTimeoutHandler() { 129 bool status = false; 130 if (num_requests_received_ >= kMinArpRequestsPerCycle) { 131 num_requests_received_ = 0; 132 num_cycles_passed_++; 133 if (num_cycles_passed_ < num_cycles_to_monitor_) { 134 // Continue on with the next cycle. 135 StartArpClient(); 136 dispatcher_->PostDelayedTask(monitor_cycle_timeout_callback_.callback(), 137 kCyclePeriodMilliseconds); 138 return; 139 } 140 // Monitor completed. 141 status = true; 142 } 143 144 // Post a task to perform cleanup and invoke result callback, since this 145 // function is invoked from the callback that will be cancelled during 146 // cleanup. 147 monitor_completed_callback_.Reset( 148 Bind(&PassiveLinkMonitor::MonitorCompleted, Unretained(this), status)); 149 dispatcher_->PostTask(monitor_completed_callback_.callback()); 150 } 151 152 void PassiveLinkMonitor::MonitorCompleted(bool status) { 153 // Stop the monitoring before invoking result callback, so that the ARP client 154 // is stopped by the time result callback is invoked. 155 Stop(); 156 result_callback_.Run(status); 157 } 158 159 } // namespace shill 160