blob: 3d422aef39f4a2aac4081fb660d1495640b3b8ee [file] [log] [blame]
// Copyright 2021 The Chromium OS 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 "missive/missive_daemon.h"
#include <cstdlib>
#include <deque>
#include <fcntl.h>
#include <string>
#include <sys/socket.h>
#include <sys/types.h>
#include <type_traits>
#include <utility>
#include <vector>
#include <chromeos/dbus/service_constants.h>
#include "missive/dbus/upload_client.h"
#include "missive/encryption/encryption_module.h"
#include "missive/encryption/verification.h"
#include "missive/proto/interface.pb.h"
#include "missive/scheduler/enqueue_job.h"
#include "missive/scheduler/scheduler.h"
#include "missive/scheduler/upload_job.h"
#include "missive/storage/storage_configuration.h"
#include "missive/storage/storage_module.h"
#include "missive/storage/storage_module_interface.h"
#include "missive/storage/storage_uploader_interface.h"
#include "missive/util/status.h"
#include "missive/util/statusor.h"
namespace reporting {
namespace {
constexpr const char kReportingDirectory[] = "/var/cache/reporting";
} // namespace
MissiveDaemon::MissiveDaemon()
: brillo::DBusServiceDaemon(::missive::kMissiveServiceName),
org::chromium::MissivedAdaptor(this),
upload_client_(UploadClient::Create()) {}
MissiveDaemon::~MissiveDaemon() = default;
void MissiveDaemon::RegisterDBusObjectsAsync(
brillo::dbus_utils::AsyncEventSequencer* sequencer) {
dbus_object_ = std::make_unique<brillo::dbus_utils::DBusObject>(
/*object_manager=*/nullptr, bus_,
org::chromium::MissivedAdaptor::GetObjectPath());
RegisterWithDBusObject(dbus_object_.get());
dbus_object_->RegisterAsync(
sequencer->GetHandler(/*descriptive_message=*/"RegisterAsync failed.",
/*failure_is_fatal=*/true));
base::FilePath reporting_path(kReportingDirectory);
StorageModule::Create(
StorageOptions()
.set_directory(reporting_path)
.set_signature_verification_public_key(
SignatureVerifier::VerificationKey()),
base::BindRepeating(&MissiveDaemon::AsyncStartUpload,
weak_factory_.GetWeakPtr()),
EncryptionModule::Create(),
base::BindOnce(&MissiveDaemon::OnStorageModuleConfigured,
weak_factory_.GetWeakPtr()));
}
void MissiveDaemon::OnStorageModuleConfigured(
StatusOr<scoped_refptr<StorageModuleInterface>> storage_module_result) {
if (!storage_module_result.ok()) {
LOG(ERROR) << "Unable to start Missive daemon status: "
<< storage_module_result.status();
return;
}
storage_module_ = std::move(storage_module_result.ValueOrDie());
daemon_is_ready_ = true;
}
void MissiveDaemon::AsyncStartUpload(
Priority priority,
bool need_encryption_key,
UploaderInterface::UploaderInterfaceResultCb uploader_result_cb) {
auto upload_job_result = UploadJob::Create(
upload_client_, need_encryption_key, std::move(uploader_result_cb));
if (!upload_job_result.ok()) {
// In the event that UploadJob::Create fails, it will call
// |uploader_result_cb| with a failure status.
LOG(ERROR) << "UploadJob was unable to create status:"
<< upload_job_result.status();
return;
}
scheduler_.EnqueueJob(std::move(upload_job_result.ValueOrDie()));
}
void MissiveDaemon::EnqueueRecords(
std::unique_ptr<brillo::dbus_utils::DBusMethodResponse<
reporting::EnqueueRecordResponse>> response,
const reporting::EnqueueRecordRequest& in_request) {
if (!daemon_is_ready_) {
reporting::EnqueueRecordResponse response_body;
auto* status = response_body.mutable_status();
status->set_code(error::UNAVAILABLE);
status->set_error_message("The daemon is still starting.");
response->Return(response_body);
return;
}
if (!in_request.has_record()) {
reporting::EnqueueRecordResponse response_body;
auto* status = response_body.mutable_status();
status->set_code(error::INVALID_ARGUMENT);
status->set_error_message("Request had no Record");
response->Return(response_body);
return;
}
if (!in_request.has_priority()) {
reporting::EnqueueRecordResponse response_body;
auto* status = response_body.mutable_status();
status->set_code(error::INVALID_ARGUMENT);
status->set_error_message("Request had no Priority");
response->Return(response_body);
return;
}
scheduler_.EnqueueJob(std::make_unique<EnqueueJob>(
storage_module_, in_request,
std::make_unique<EnqueueJob::EnqueueResponseDelegate>(
std::move(response))));
}
void MissiveDaemon::FlushPriority(
std::unique_ptr<brillo::dbus_utils::DBusMethodResponse<
reporting::FlushPriorityResponse>> response,
const reporting::FlushPriorityRequest& in_request) {
if (!daemon_is_ready_) {
reporting::FlushPriorityResponse response_body;
auto* status = response_body.mutable_status();
status->set_code(error::UNAVAILABLE);
status->set_error_message("The daemon is still starting.");
response->Return(response_body);
return;
}
storage_module_->Flush(
in_request.priority(),
base::BindOnce(&MissiveDaemon::HandleFlushResponse,
weak_factory_.GetWeakPtr(), std::move(response)));
}
void MissiveDaemon::HandleFlushResponse(
std::unique_ptr<brillo::dbus_utils::DBusMethodResponse<
reporting::FlushPriorityResponse>> response,
Status status) const {
reporting::FlushPriorityResponse response_body;
status.SaveTo(response_body.mutable_status());
response->Return(response_body);
}
void MissiveDaemon::ConfirmRecordUpload(
std::unique_ptr<brillo::dbus_utils::DBusMethodResponse<
reporting::ConfirmRecordUploadResponse>> response,
const reporting::ConfirmRecordUploadRequest& in_request) {
ConfirmRecordUploadResponse response_body;
if (!daemon_is_ready_) {
auto* status = response_body.mutable_status();
status->set_code(error::UNAVAILABLE);
status->set_error_message("The daemon is still starting.");
response->Return(response_body);
return;
}
if (!in_request.has_sequencing_information()) {
auto* status = response_body.mutable_status();
status->set_code(error::INVALID_ARGUMENT);
status->set_error_message("Request had no SequencingInformation");
response->Return(response_body);
return;
}
storage_module_->ReportSuccess(in_request.sequencing_information(),
in_request.force_confirm());
response->Return(response_body);
}
void MissiveDaemon::UpdateEncryptionKey(
std::unique_ptr<brillo::dbus_utils::DBusMethodResponse<
reporting::UpdateEncryptionKeyResponse>> response,
const reporting::UpdateEncryptionKeyRequest& in_request) {
reporting::UpdateEncryptionKeyResponse response_body;
if (!daemon_is_ready_) {
auto* status = response_body.mutable_status();
status->set_code(error::UNAVAILABLE);
status->set_error_message("The daemon is still starting.");
response->Return(response_body);
return;
}
if (!in_request.has_signed_encryption_info()) {
auto status = response_body.mutable_status();
status->set_code(error::INVALID_ARGUMENT);
status->set_error_message("Request had no SignedEncryptionInfo");
response->Return(response_body);
return;
}
storage_module_->UpdateEncryptionKey(in_request.signed_encryption_info());
response->Return(response_body);
}
} // namespace reporting