blob: 77dea71729ac5e1fab28cfd3bf9fabd704465b49 [file] [log] [blame]
// Copyright 2014 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 "peerd/service.h"
#include <base/strings/string_util.h>
#include <chromeos/dbus/exported_object_manager.h>
#include "peerd/dbus_constants.h"
using chromeos::Error;
using chromeos::dbus_utils::AsyncEventSequencer;
using chromeos::dbus_utils::DBusInterface;
using chromeos::dbus_utils::DBusObject;
using chromeos::dbus_utils::ExportedObjectManager;
using dbus::ObjectPath;
using peerd::dbus_constants::kServiceId;
using peerd::dbus_constants::kServiceInfo;
using peerd::dbus_constants::kServiceInterface;
using peerd::dbus_constants::kServiceIpInfos;
using std::string;
using std::unique_ptr;
namespace {
const char kValidServiceIdCharacters[] = "abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789"
"-";
const char kValidServiceInfoKeyCharacters[] = "abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789"
"_";
} // namespace
namespace peerd {
namespace errors {
namespace service {
const char kInvalidServiceId[] = "service.id";
const char kInvalidServiceInfo[] = "service.info";
} // namespace service
} // namespace errors
Service::Service(const scoped_refptr<dbus::Bus>& bus,
chromeos::dbus_utils::ExportedObjectManager* object_manager,
const dbus::ObjectPath& path)
: dbus_object_(new DBusObject{object_manager, bus, path}) {
}
bool Service::RegisterAsync(chromeos::ErrorPtr* error,
const std::string& service_id,
const IpAddresses& addresses,
const ServiceInfo& service_info,
const CompletionAction& completion_callback) {
if (!IsValidServiceId(error, service_id)) { return false; }
if (!IsValidServiceInfo(error, service_info)) { return false; }
service_id_.SetValue(service_id);
ip_addresses_.SetValue(addresses);
service_info_.SetValue(service_info);
DBusInterface* itf = dbus_object_->AddOrGetInterface(kServiceInterface);
itf->AddProperty(kServiceId, &service_id_);
itf->AddProperty(kServiceIpInfos, &ip_addresses_);
itf->AddProperty(kServiceInfo, &service_info_);
dbus_object_->RegisterAsync(completion_callback);
return true;
}
const std::string& Service::GetServiceId() const {
return service_id_.value();
}
const Service::IpAddresses& Service::GetIpAddresses() const {
return ip_addresses_.value();
}
const Service::ServiceInfo& Service::GetServiceInfo() const {
return service_info_.value();
}
bool Service::Update(chromeos::ErrorPtr* error,
const IpAddresses& addresses,
const ServiceInfo& info) {
if (!IsValidServiceInfo(error, info)) {
return false;
}
ip_addresses_.SetValue(addresses);
service_info_.SetValue(info);
return true;
}
bool Service::IsValidServiceId(chromeos::ErrorPtr* error,
const std::string& service_id) {
// From RFC 6335 (mDNS service names):
// Valid service names are hereby normatively defined as follows:
//
// o MUST be at least 1 character and no more than 15 characters long
// o MUST contain only US-ASCII [ANSI.X3.4-1986] letters 'A' - 'Z' and
// 'a' - 'z', digits '0' - '9', and hyphens ('-', ASCII 0x2D or
// decimal 45)
// o MUST contain at least one letter ('A' - 'Z' or 'a' - 'z')
// o MUST NOT begin or end with a hyphen
// o hyphens MUST NOT be adjacent to other hyphens
if (service_id.empty() || service_id.length() > kMaxServiceIdLength) {
Error::AddTo(error,
kPeerdErrorDomain,
errors::service::kInvalidServiceId,
"Invalid service ID length.");
return false;
}
if (!base::ContainsOnlyChars(service_id, kValidServiceIdCharacters)) {
Error::AddTo(error,
kPeerdErrorDomain,
errors::service::kInvalidServiceId,
"Invalid character in service ID.");
return false;
}
if (service_id.front() == '-' || service_id.back() == '-') {
Error::AddTo(error,
kPeerdErrorDomain,
errors::service::kInvalidServiceId,
"Service ID may not start or end with hyphens.");
return false;
}
if (service_id.find("--") != string::npos) {
Error::AddTo(error,
kPeerdErrorDomain,
errors::service::kInvalidServiceId,
"Service ID may not contain adjacent hyphens.");
return false;
}
return true;
}
bool Service::IsValidServiceInfo(chromeos::ErrorPtr* error,
const ServiceInfo& service_info) {
for (const auto& kv : service_info) {
if (kv.first.length() + kv.second.length() > kMaxServiceInfoPairLength) {
Error::AddTo(error,
kPeerdErrorDomain,
errors::service::kInvalidServiceInfo,
"Invalid service info pair length.");
return false;
}
if (!base::ContainsOnlyChars(kv.first, kValidServiceInfoKeyCharacters)) {
Error::AddTo(error,
kPeerdErrorDomain,
errors::service::kInvalidServiceInfo,
"Invalid service key.");
return false;
}
}
return true;
}
} // namespace peerd