summaryrefslogtreecommitdiff
path: root/manager.cc
blob: a4c8b4839614b776a93a8f42722c557d52d32d4e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
//
// Copyright (C) 2014 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 "apmanager/manager.h"

#include <base/bind.h>

#if !defined(__ANDROID__)
#include <chromeos/dbus/service_constants.h>
#else
#include "dbus/apmanager/dbus-constants.h"
#endif  // __ANDROID__

using brillo::dbus_utils::AsyncEventSequencer;
using brillo::dbus_utils::ExportedObjectManager;
using brillo::dbus_utils::DBusMethodResponse;
using std::string;

namespace apmanager {

Manager::Manager()
    : org::chromium::apmanager::ManagerAdaptor(this),
      service_identifier_(0),
      device_identifier_(0),
      device_info_(this) {}

Manager::~Manager() {
  // Terminate all services before cleanup other resources.
  for (auto& service : services_) {
    service.reset();
  }
}

void Manager::RegisterAsync(ExportedObjectManager* object_manager,
                            const scoped_refptr<dbus::Bus>& bus,
                            AsyncEventSequencer* sequencer) {
  CHECK(!dbus_object_) << "Already registered";
  dbus_object_.reset(
      new brillo::dbus_utils::DBusObject(
          object_manager,
          bus,
          org::chromium::apmanager::ManagerAdaptor::GetObjectPath()));
  RegisterWithDBusObject(dbus_object_.get());
  dbus_object_->RegisterAsync(
      sequencer->GetHandler("Manager.RegisterAsync() failed.", true));
  bus_ = bus;

  shill_manager_.Init(bus);
  firewall_manager_.Init(bus);
}

void Manager::Start() {
  device_info_.Start();
}

void Manager::Stop() {
  device_info_.Stop();
}

void Manager::CreateService(
    std::unique_ptr<DBusMethodResponse<dbus::ObjectPath>> response,
    dbus::Message* message) {
  LOG(INFO) << "Manager::CreateService";
  scoped_refptr<AsyncEventSequencer> sequencer(new AsyncEventSequencer());
  std::unique_ptr<Service> service(new Service(this, service_identifier_));

  service->RegisterAsync(
      dbus_object_->GetObjectManager().get(), bus_, sequencer.get());
  sequencer->OnAllTasksCompletedCall({
      base::Bind(&Manager::OnServiceRegistered,
                 base::Unretained(this),
                 base::Passed(&response),
                 base::Passed(&service))
  });

  base::Closure on_connection_vanish = base::Bind(
      &Manager::OnAPServiceOwnerDisappeared,
      base::Unretained(this),
      service_identifier_);
  service_watchers_[service_identifier_].reset(
      new DBusServiceWatcher{bus_, message->GetSender(), on_connection_vanish});
  service_identifier_++;
}

bool Manager::RemoveService(brillo::ErrorPtr* error,
                            dbus::Message* message,
                            const dbus::ObjectPath& in_service) {
  for (auto it = services_.begin(); it != services_.end(); ++it) {
    if ((*it)->dbus_path() == in_service) {
      // Verify the owner.
      auto watcher = service_watchers_.find((*it)->identifier());
      CHECK(watcher != service_watchers_.end())
          << "DBus watcher not created for service: " << (*it)->identifier();
      if (watcher->second->connection_name() != message->GetSender()) {
        brillo::Error::AddToPrintf(
            error, FROM_HERE, brillo::errors::dbus::kDomain, kManagerError,
            "Service %d is owned by another local process.",
            (*it)->identifier());
        return false;
      }
      service_watchers_.erase(watcher);

      services_.erase(it);
      return true;
    }
  }

  brillo::Error::AddTo(
      error, FROM_HERE, brillo::errors::dbus::kDomain, kManagerError,
      "Service does not exist");
  return false;
}

scoped_refptr<Device> Manager::GetAvailableDevice() {
  for (const auto& device : devices_) {
    // Look for an unused device with AP interface mode support.
    if (!device->GetInUse() && !device->GetPreferredApInterface().empty()) {
      return device;
    }
  }
  return nullptr;
}

scoped_refptr<Device> Manager::GetDeviceFromInterfaceName(
    const string& interface_name) {
  for (const auto& device : devices_) {
    if (device->InterfaceExists(interface_name)) {
      return device;
    }
  }
  return nullptr;
}

void Manager::RegisterDevice(scoped_refptr<Device> device) {
  LOG(INFO) << "Manager::RegisterDevice: registering device "
            << device->GetDeviceName();
  // Register device DBbus interfaces.
  scoped_refptr<AsyncEventSequencer> sequencer(new AsyncEventSequencer());
  device->RegisterAsync(dbus_object_->GetObjectManager().get(),
                        bus_,
                        sequencer.get(),
                        device_identifier_++);
  sequencer->OnAllTasksCompletedCall({
    base::Bind(&Manager::OnDeviceRegistered,
               base::Unretained(this),
               device)
  });
}

void Manager::ClaimInterface(const string& interface_name) {
  shill_manager_.ClaimInterface(interface_name);
}

void Manager::ReleaseInterface(const string& interface_name) {
  shill_manager_.ReleaseInterface(interface_name);
}

void Manager::RequestDHCPPortAccess(const string& interface) {
  firewall_manager_.RequestDHCPPortAccess(interface);
}

void Manager::ReleaseDHCPPortAccess(const string& interface) {
  firewall_manager_.ReleaseDHCPPortAccess(interface);
}

void Manager::OnServiceRegistered(
    std::unique_ptr<DBusMethodResponse<dbus::ObjectPath>> response,
    std::unique_ptr<Service> service,
    bool success) {
  LOG(INFO) << "ServiceRegistered";
  // Success should always be true since we've said that failures are fatal.
  CHECK(success) << "Init of one or more objects has failed.";

  // Remove this service if the owner doesn't exist anymore. It is theoretically
  // possible to have the owner disappear before the AP service complete its
  // registration with DBus.
  if (service_watchers_.find(service->identifier()) ==
      service_watchers_.end()) {
    LOG(INFO) << "Service " << service->identifier()
              << ": owner doesn't exist anymore";
    service.reset();
    return;
  }

  // Add service to the service list and return the service dbus path for the
  // CreateService call.
  dbus::ObjectPath service_path = service->dbus_path();
  services_.push_back(std::move(service));
  response->Return(service_path);
}

void Manager::OnDeviceRegistered(scoped_refptr<Device> device, bool success) {
  // Success should always be true since we've said that failures are fatal.
  CHECK(success) << "Init of one or more objects has failed.";

  devices_.push_back(device);
  // TODO(zqiu): Property update for available devices.
}

void Manager::OnAPServiceOwnerDisappeared(int service_identifier) {
  LOG(INFO) << "Owner for service " << service_identifier << " disappeared";
  // Remove service watcher.
  auto watcher = service_watchers_.find(service_identifier);
  CHECK(watcher != service_watchers_.end())
      << "Owner disappeared without watcher setup";
  service_watchers_.erase(watcher);

  // Remove the service.
  for (auto it = services_.begin(); it != services_.end(); ++it) {
    if ((*it)->identifier() == service_identifier) {
      services_.erase(it);
      return;
    }
  }
  LOG(INFO) << "Owner for service " << service_identifier
            << " disappeared before it is registered";
}

}  // namespace apmanager