Home | History | Annotate | Download | only in dbus
      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/dbus/chromeos_dhcpcd_listener.h"
     18 
     19 #include <string.h>
     20 
     21 #include <base/bind.h>
     22 #include <base/callback.h>
     23 #include <base/strings/stringprintf.h>
     24 #include <brillo/dbus/dbus_method_invoker.h>
     25 #include <dbus/util.h>
     26 
     27 #include "shill/dhcp/dhcp_config.h"
     28 #include "shill/dhcp/dhcp_provider.h"
     29 #include "shill/event_dispatcher.h"
     30 #include "shill/logging.h"
     31 
     32 using std::string;
     33 
     34 namespace shill {
     35 
     36 namespace Logging {
     37 static auto kModuleLogScope = ScopeLogger::kDHCP;
     38 static string ObjectID(ChromeosDHCPCDListener* d) {
     39   return "(dhcpcd_listener)";
     40 }
     41 }
     42 
     43 const char ChromeosDHCPCDListener::kDBusInterfaceName[] = "org.chromium.dhcpcd";
     44 const char ChromeosDHCPCDListener::kSignalEvent[] = "Event";
     45 const char ChromeosDHCPCDListener::kSignalStatusChanged[] = "StatusChanged";
     46 
     47 ChromeosDHCPCDListener::ChromeosDHCPCDListener(
     48     const scoped_refptr<dbus::Bus>& bus,
     49     EventDispatcher* dispatcher,
     50     DHCPProvider* provider)
     51     : bus_(bus),
     52       dispatcher_(dispatcher),
     53       provider_(provider),
     54       match_rule_(base::StringPrintf("type='signal', interface='%s'",
     55                                      kDBusInterfaceName)) {
     56   bus_->AssertOnDBusThread();
     57   CHECK(bus_->SetUpAsyncOperations());
     58   if (!bus_->is_connected()) {
     59     LOG(FATAL) << "DBus isn't connected.";
     60   }
     61 
     62   // Register filter function to the bus.  It will be called when incoming
     63   // messages are received.
     64   bus_->AddFilterFunction(&ChromeosDHCPCDListener::HandleMessageThunk, this);
     65 
     66   // Add match rule to the bus.
     67   dbus::ScopedDBusError error;
     68   bus_->AddMatch(match_rule_, error.get());
     69   if (error.is_set()) {
     70     LOG(FATAL) << "Failed to add match rule: " << error.name() << " "
     71                << error.message();
     72   }
     73 }
     74 
     75 ChromeosDHCPCDListener::~ChromeosDHCPCDListener() {
     76   bus_->RemoveFilterFunction(&ChromeosDHCPCDListener::HandleMessageThunk, this);
     77   dbus::ScopedDBusError error;
     78   bus_->RemoveMatch(match_rule_, error.get());
     79   if (error.is_set()) {
     80     LOG(FATAL) << "Failed to remove match rule: " << error.name() << " "
     81                << error.message();
     82   }
     83 }
     84 
     85 // static.
     86 DBusHandlerResult ChromeosDHCPCDListener::HandleMessageThunk(
     87     DBusConnection* connection, DBusMessage* raw_message, void* user_data) {
     88   ChromeosDHCPCDListener* self =
     89       static_cast<ChromeosDHCPCDListener*>(user_data);
     90   return self->HandleMessage(connection, raw_message);
     91 }
     92 
     93 DBusHandlerResult ChromeosDHCPCDListener::HandleMessage(
     94     DBusConnection* connection, DBusMessage* raw_message) {
     95   bus_->AssertOnDBusThread();
     96 
     97   // Only interested in signal message.
     98   if (dbus_message_get_type(raw_message) != DBUS_MESSAGE_TYPE_SIGNAL) {
     99     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    100   }
    101 
    102   // raw_message will be unrefed in Signal's parent class's (dbus::Message)
    103   // destructor. Increment the reference so we can use it in Signal.
    104   dbus_message_ref(raw_message);
    105   std::unique_ptr<dbus::Signal> signal(
    106       dbus::Signal::FromRawMessage(raw_message));
    107 
    108   // Verify the signal comes from the interface that we interested in.
    109   if (signal->GetInterface() != kDBusInterfaceName) {
    110     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    111   }
    112 
    113   string sender = signal->GetSender();
    114   string member_name = signal->GetMember();
    115   dbus::MessageReader reader(signal.get());
    116   if (member_name == kSignalEvent) {
    117     uint32_t pid;
    118     string reason;
    119     brillo::VariantDictionary configurations;
    120     // ExtracMessageParameters will log the error if it failed.
    121     if (brillo::dbus_utils::ExtractMessageParameters(&reader,
    122                                                      nullptr,
    123                                                      &pid,
    124                                                      &reason,
    125                                                      &configurations)) {
    126       dispatcher_->PostTask(
    127           base::Bind(&ChromeosDHCPCDListener::EventSignal,
    128                      weak_factory_.GetWeakPtr(),
    129                      sender, pid, reason, configurations));
    130     }
    131   } else if (member_name == kSignalStatusChanged) {
    132     uint32_t pid;
    133     string status;
    134     // ExtracMessageParameters will log the error if it failed.
    135     if (brillo::dbus_utils::ExtractMessageParameters(&reader,
    136                                                      nullptr,
    137                                                      &pid,
    138                                                      &status)) {
    139       dispatcher_->PostTask(
    140           base::Bind(&ChromeosDHCPCDListener::StatusChangedSignal,
    141                      weak_factory_.GetWeakPtr(),
    142                      sender, pid, status));
    143     }
    144   } else {
    145     LOG(INFO) << "Ignore signal: " << member_name;
    146   }
    147 
    148   return DBUS_HANDLER_RESULT_HANDLED;
    149 }
    150 
    151 void ChromeosDHCPCDListener::EventSignal(
    152     const string& sender,
    153     uint32_t pid,
    154     const string& reason,
    155     const brillo::VariantDictionary& configuration) {
    156   DHCPConfigRefPtr config = provider_->GetConfig(pid);
    157   if (!config.get()) {
    158     if (provider_->IsRecentlyUnbound(pid)) {
    159       SLOG(nullptr, 3)
    160           << __func__ << ": ignoring message from recently unbound PID " << pid;
    161     } else {
    162       LOG(ERROR) << "Unknown DHCP client PID " << pid;
    163     }
    164     return;
    165   }
    166   config->InitProxy(sender);
    167   KeyValueStore configuration_store;
    168   KeyValueStore::ConvertFromVariantDictionary(configuration,
    169                                               &configuration_store);
    170   config->ProcessEventSignal(reason, configuration_store);
    171 }
    172 
    173 void ChromeosDHCPCDListener::StatusChangedSignal(const string& sender,
    174                                                  uint32_t pid,
    175                                                  const string& status) {
    176   DHCPConfigRefPtr config = provider_->GetConfig(pid);
    177   if (!config.get()) {
    178     if (provider_->IsRecentlyUnbound(pid)) {
    179       SLOG(nullptr, 3)
    180           << __func__ << ": ignoring message from recently unbound PID " << pid;
    181     } else {
    182       LOG(ERROR) << "Unknown DHCP client PID " << pid;
    183     }
    184     return;
    185   }
    186   config->InitProxy(sender);
    187   config->ProcessStatusChangeSignal(status);
    188 }
    189 
    190 }  // namespace shill
    191