blob: 55740400a95f3d4bb682ac87ba76149682d1bdb3 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <lib/fdio/directory.h>
#include <lib/sys/service/cpp/service_aggregate.h>
#include <lib/sys/service/cpp/service_watcher.h>
namespace sys {
zx_status_t ServiceWatcher::Begin(const ServiceAggregateBase& service_aggregate,
async_dispatcher_t* dispatcher) {
fidl::SynchronousInterfacePtr<fuchsia::io::DirectoryWatcher> watcher;
fidl::SynchronousInterfacePtr<fuchsia::io::Directory> dir;
dir.Bind(zx::channel(fdio_service_clone(service_aggregate.channel().get())));
zx_status_t fidl_status;
zx_status_t status = dir->Watch(fuchsia::io::WatchMask::EXISTING | fuchsia::io::WatchMask::ADDED |
fuchsia::io::WatchMask::REMOVED,
0, watcher.NewRequest(), &fidl_status);
if (status != ZX_OK) {
return status;
}
if (fidl_status != ZX_OK) {
return fidl_status;
}
buf_.resize(fuchsia::io::MAX_BUF);
client_end_ = watcher.Unbind().TakeChannel();
wait_.set_object(client_end_.get());
wait_.set_trigger(ZX_CHANNEL_READABLE);
return wait_.Begin(dispatcher);
}
zx_status_t ServiceWatcher::Cancel() { return wait_.Cancel(); }
void ServiceWatcher::OnWatchedEvent(async_dispatcher_t* dispatcher, async::WaitBase* wait,
zx_status_t status, const zx_packet_signal_t* signal) {
if (status != ZX_OK || !(signal->observed & ZX_CHANNEL_READABLE)) {
return;
}
uint32_t size = buf_.size();
status = client_end_.read(0, buf_.data(), nullptr, size, 0, &size, nullptr);
if (status != ZX_OK) {
return;
}
for (auto i = buf_.begin(), end = buf_.begin() + size; std::distance(i, end) > 2;) {
// Process message structure, as described by fuchsia::io::WatchedEvent.
fuchsia::io::WatchEvent event = static_cast<fuchsia::io::WatchEvent>(*i++);
uint8_t len = *i++;
// Restrict the length to the remaining size of the buffer.
len = std::min<uint8_t>(len, std::max(0l, std::distance(i, end)));
// If the entry is valid, invoke the callback.
if (len != 1 || *i != '.') {
std::string instance(reinterpret_cast<char*>(i.base()), len);
callback_(event, std::move(instance));
}
i += len;
}
wait_.Begin(dispatcher);
}
} // namespace sys