[common] adding Heap::Allocatable and use it in Srp::Server (#7168)

This commit adds a new class `Heap::Allocatable<Type>` which provides
`New()` and `Free()` methods to allocate and free instances of a
template `Type` on heap. The static `New()` method requires the
`Type` class to provide a method `Error Init(Args...)` to initialize
the allocated object as `Type`. The initialization itself can fail
(return `Error`) in which case `New()` will release any allocated
buffer and return `nullptr`. The `Free()` method invokes the `Type`
class's destructor before releasing the heap pointer. This ensures
that any heap allocated member variables in `Type` (e.g., any
`Heap::String` or `Heap::Data`) are freed before the `Type` instance
itself is freed.
This commit is contained in:
Abtin Keshavarzian
2021-11-19 10:32:38 -08:00
committed by GitHub
parent ed5e5bbb6d
commit ccceb5f054
5 changed files with 205 additions and 162 deletions
+1
View File
@@ -389,6 +389,7 @@ openthread_core_files = [
"common/extension.hpp",
"common/heap.cpp",
"common/heap.hpp",
"common/heap_allocatable.hpp",
"common/heap_data.cpp",
"common/heap_data.hpp",
"common/heap_string.cpp",
+1
View File
@@ -429,6 +429,7 @@ HEADERS_COMMON = \
common/error.hpp \
common/extension.hpp \
common/heap.hpp \
common/heap_allocatable.hpp \
common/heap_data.hpp \
common/heap_string.hpp \
common/instance.hpp \
+116
View File
@@ -0,0 +1,116 @@
/*
* Copyright (c) 2021, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file includes definitions for `Heap::Allocatable`.
*/
#ifndef HEAP_ALLOCATABLE_HPP_
#define HEAP_ALLOCATABLE_HPP_
#include "openthread-core-config.h"
#include "common/code_utils.hpp"
#include "common/error.hpp"
#include "common/heap.hpp"
#include "common/new.hpp"
namespace ot {
namespace Heap {
/**
* This template class defines a `Heap::Allocatable` object.
*
* `Heap::Allocatable` provides `New()` and `Free()` methods to allocate and free instances of `Type` on heap.
*
* Users of this class should follow CRTP-style inheritance, i.e., the `Type` class itself should inherit from
* `Allocatable<Type>`.
*
* The `Type` class destructor is used when `Free()` is called. The destructor frees any heap allocated data members
* that are stored in a `Type` instance (e.g., `Heap::String`, `Heap::Data`, etc).
*
*/
template <class Type> class Allocatable
{
public:
/**
* This static method allocates a new instance of `Type` on heap and initializes it.
*
* The `Type` class MUST have a default constructor (with no arguments) which is invoked upon allocation of new
* `Type` instance. It MUST also provide an `Error Init(Args...)` method to initialize the instance. If any `Error`
* other than `kErrorNone` is returned the initialization is considered failed.
*
* @param[in] aArgs A set of arguments to initialize the allocated `Type` instance.
*
* @returns A pointer to the newly allocated instance or `nullptr` if it fails to allocate or initialize.
*
*/
template <typename... Args> static Type *New(Args &&... aArgs)
{
void *buf = Heap::CAlloc(1, sizeof(Type));
Type *object = nullptr;
VerifyOrExit(buf != nullptr);
object = new (buf) Type();
if (object->Init(static_cast<Args &&>(aArgs)...) != kErrorNone)
{
object->Free();
object = nullptr;
}
exit:
return object;
}
/**
* This method frees the `Type` instance.
*
* The instance MUST be heap allocated using the `New()` method.
*
* The `Free()` method invokes the `Type` destructor before releasing the allocated heap buffer for the instance.
* This ensures that any heap allocated member variables in `Type` are freed before the `Type` instance itself is
* freed.
*
*/
void Free(void)
{
static_cast<Type *>(this)->~Type();
Heap::Free(this);
}
protected:
Allocatable(void) = default;
};
} // namespace Heap
} // namespace ot
#endif // HEAP_ALLOCATABLE_HPP_
+47 -126
View File
@@ -1144,8 +1144,8 @@ void Server::HandleUpdate(Host &aHost, const MessageMetadata &aMetadata)
service.IsSubType(), aMetadata.mRxTime);
VerifyOrExit(newService != nullptr, error = kErrorNoBufs);
newService->mDescription.mUpdateTime = aMetadata.mRxTime;
newService->mIsDeleted = true;
newService->mDescription->mUpdateTime = aMetadata.mRxTime;
newService->mIsDeleted = true;
}
}
@@ -1444,43 +1444,16 @@ const char *Server::AddressModeToString(AddressMode aMode)
//---------------------------------------------------------------------------------------------------------------------
// Server::Service
Server::Service *Server::Service::New(const char * aServiceName,
Description &aDescription,
bool aIsSubType,
TimeMilli aUpdateTime)
Error Server::Service::Init(const char *aServiceName, Description &aDescription, bool aIsSubType, TimeMilli aUpdateTime)
{
void * buf;
Service *service = nullptr;
mDescription = &aDescription;
mNext = nullptr;
mUpdateTime = aUpdateTime;
mIsDeleted = false;
mIsSubType = aIsSubType;
mIsCommitted = false;
buf = Heap::CAlloc(1, sizeof(Service));
VerifyOrExit(buf != nullptr);
service = new (buf) Service(aDescription, aIsSubType, aUpdateTime);
if (service->mServiceName.Set(aServiceName) != kErrorNone)
{
service->Free();
service = nullptr;
}
exit:
return service;
}
void Server::Service::Free(void)
{
mServiceName.Free();
Heap::Free(this);
}
Server::Service::Service(Description &aDescription, bool aIsSubType, TimeMilli aUpdateTime)
: mDescription(aDescription)
, mNext(nullptr)
, mUpdateTime(aUpdateTime)
, mIsDeleted(false)
, mIsSubType(aIsSubType)
, mIsCommitted(false)
{
return mServiceName.Set(aServiceName);
}
Error Server::Service::GetServiceSubTypeLabel(char *aLabel, uint8_t aMaxSize) const
@@ -1518,12 +1491,12 @@ TimeMilli Server::Service::GetExpireTime(void) const
OT_ASSERT(!mIsDeleted);
OT_ASSERT(!GetHost().IsDeleted());
return mUpdateTime + Time::SecToMsec(mDescription.mLease);
return mUpdateTime + Time::SecToMsec(mDescription->mLease);
}
TimeMilli Server::Service::GetKeyExpireTime(void) const
{
return mUpdateTime + Time::SecToMsec(mDescription.mKeyLease);
return mUpdateTime + Time::SecToMsec(mDescription->mKeyLease);
}
bool Server::Service::MatchesFlags(Flags aFlags) const
@@ -1597,43 +1570,19 @@ void Server::Service::Log(Action) const
//---------------------------------------------------------------------------------------------------------------------
// Server::Service::Description
Server::Service::Description *Server::Service::Description::New(const char *aInstanceName, Host &aHost)
Error Server::Service::Description::Init(const char *aInstanceName, Host &aHost)
{
void * buf;
Description *desc = nullptr;
buf = Heap::CAlloc(1, sizeof(Description));
VerifyOrExit(buf != nullptr);
desc = new (buf) Description(aHost);
if (desc->mInstanceName.Set(aInstanceName) != kErrorNone)
{
desc->Free();
desc = nullptr;
}
exit:
return desc;
}
void Server::Service::Description::Free(void)
{
mInstanceName.Free();
mNext = nullptr;
mHost = &aHost;
mPriority = 0;
mWeight = 0;
mPort = 0;
mLease = 0;
mKeyLease = 0;
mUpdateTime = TimerMilli::GetNow().GetDistantPast();
mTxtData.Free();
Heap::Free(this);
}
Server::Service::Description::Description(Host &aHost)
: mNext(nullptr)
, mHost(aHost)
, mPriority(0)
, mWeight(0)
, mPort(0)
, mLease(0)
, mKeyLease(0)
, mUpdateTime(TimerMilli::GetNow().GetDistantPast())
{
return mInstanceName.Set(aInstanceName);
}
void Server::Service::Description::ClearResources(void)
@@ -1675,35 +1624,25 @@ exit:
//---------------------------------------------------------------------------------------------------------------------
// Server::Host
Server::Host *Server::Host::New(Instance &aInstance, TimeMilli aUpdateTime)
Error Server::Host::Init(Instance &aInstance, TimeMilli aUpdateTime)
{
void *buf;
Host *host = nullptr;
InstanceLocatorInit::Init(aInstance);
mNext = nullptr;
mFullName.Free();
mAddresses.Clear();
mKey.Clear();
mLease = 0;
mKeyLease = 0;
mUpdateTime = aUpdateTime;
mServices.Clear();
mServiceDescriptions.Clear();
buf = Heap::CAlloc(1, sizeof(Host));
VerifyOrExit(buf != nullptr);
host = new (buf) Host(aInstance, aUpdateTime);
exit:
return host;
return kErrorNone;
}
void Server::Host::Free(void)
Server::Host::~Host(void)
{
FreeAllServices();
mFullName.Free();
Heap::Free(this);
}
Server::Host::Host(Instance &aInstance, TimeMilli aUpdateTime)
: InstanceLocator(aInstance)
, mNext(nullptr)
, mLease(0)
, mKeyLease(0)
, mUpdateTime(aUpdateTime)
{
mKey.Clear();
}
Error Server::Host::SetFullName(const char *aFullName)
@@ -1919,7 +1858,7 @@ Error Server::Host::MergeServicesAndResourcesFrom(Host &aHost)
// (1) Service description is shared across a base type and all its subtypes.
// (2) `TakeResourcesFrom()` releases resources pinned to its argument.
// Therefore, make sure the function is called only for the base type.
newService->mDescription.TakeResourcesFrom(service.mDescription);
newService->mDescription->TakeResourcesFrom(*service.mDescription);
}
newService->Log((existingService != nullptr) ? Service::kUpdateExisting : Service::kAddNew);
@@ -1977,41 +1916,23 @@ exit:
//---------------------------------------------------------------------------------------------------------------------
// Server::UpdateMetadata
Server::UpdateMetadata *Server::UpdateMetadata::New(Instance & aInstance,
Host & aHost,
const MessageMetadata &aMessageMetadata)
Error Server::UpdateMetadata::Init(Instance &aInstance, Host &aHost, const MessageMetadata &aMessageMetadata)
{
void * buf;
UpdateMetadata *update = nullptr;
InstanceLocatorInit::Init(aInstance);
mNext = nullptr;
mExpireTime = TimerMilli::GetNow() + kDefaultEventsHandlerTimeout;
mDnsHeader = aMessageMetadata.mDnsHeader;
mId = Get<Server>().AllocateId();
mLeaseConfig = aMessageMetadata.mLeaseConfig;
mHost = &aHost;
mIsDirectRxFromClient = aMessageMetadata.IsDirectRxFromClient();
buf = Heap::CAlloc(1, sizeof(UpdateMetadata));
VerifyOrExit(buf != nullptr);
update = new (buf) UpdateMetadata(aInstance, aHost, aMessageMetadata);
exit:
return update;
}
void Server::UpdateMetadata::Free(void)
{
Heap::Free(this);
}
Server::UpdateMetadata::UpdateMetadata(Instance &aInstance, Host &aHost, const MessageMetadata &aMessageMetadata)
: InstanceLocator(aInstance)
, mNext(nullptr)
, mExpireTime(TimerMilli::GetNow() + kDefaultEventsHandlerTimeout)
, mDnsHeader(aMessageMetadata.mDnsHeader)
, mId(Get<Server>().AllocateId())
, mLeaseConfig(aMessageMetadata.mLeaseConfig)
, mHost(aHost)
, mIsDirectRxFromClient(aMessageMetadata.IsDirectRxFromClient())
{
if (aMessageMetadata.mMessageInfo != nullptr)
{
mMessageInfo = *aMessageMetadata.mMessageInfo;
}
return kErrorNone;
}
} // namespace Srp
+40 -36
View File
@@ -57,6 +57,7 @@
#include "common/as_core_type.hpp"
#include "common/clearable.hpp"
#include "common/heap.hpp"
#include "common/heap_allocatable.hpp"
#include "common/heap_data.hpp"
#include "common/heap_string.hpp"
#include "common/linked_list.hpp"
@@ -151,11 +152,15 @@ public:
* This class implements a server-side SRP service.
*
*/
class Service : public otSrpServerService, public LinkedListEntry<Service>, private NonCopyable
class Service : public otSrpServerService,
public LinkedListEntry<Service>,
private Heap::Allocatable<Service>,
private NonCopyable
{
friend class Server;
friend class LinkedList<Service>;
friend class LinkedListEntry<Service>;
friend class Heap::Allocatable<Service>;
public:
/**
@@ -216,7 +221,7 @@ public:
* @returns A pointer service instance name (as a null-terminated C string).
*
*/
const char *GetInstanceName(void) const { return mDescription.mInstanceName.AsCString(); }
const char *GetInstanceName(void) const { return mDescription->mInstanceName.AsCString(); }
/**
* This method gets the full service name of the service.
@@ -251,7 +256,7 @@ public:
* @returns The port of the service.
*
*/
uint16_t GetPort(void) const { return mDescription.mPort; }
uint16_t GetPort(void) const { return mDescription->mPort; }
/**
* This method returns the weight of the service instance.
@@ -259,7 +264,7 @@ public:
* @returns The weight of the service.
*
*/
uint16_t GetWeight(void) const { return mDescription.mWeight; }
uint16_t GetWeight(void) const { return mDescription->mWeight; }
/**
* This method returns the priority of the service instance.
@@ -269,7 +274,7 @@ public:
* @returns The priority of the service.
*
*/
uint16_t GetPriority(void) const { return mDescription.mPriority; }
uint16_t GetPriority(void) const { return mDescription->mPriority; }
/**
* This method returns the TXT record data of the service instance.
@@ -277,7 +282,7 @@ public:
* @returns A pointer to the buffer containing the TXT record data.
*
*/
const uint8_t *GetTxtData(void) const { return mDescription.mTxtData.GetBytes(); }
const uint8_t *GetTxtData(void) const { return mDescription->mTxtData.GetBytes(); }
/**
* This method returns the TXT record data length of the service instance.
@@ -285,7 +290,7 @@ public:
* @return The TXT record data length (number of bytes in buffer returned from `GetTxtData()`).
*
*/
uint16_t GetTxtDataLength(void) const { return mDescription.mTxtData.GetLength(); }
uint16_t GetTxtDataLength(void) const { return mDescription->mTxtData.GetLength(); }
/**
* This method returns the host which the service instance reside on.
@@ -293,7 +298,7 @@ public:
* @returns A reference to the host instance.
*
*/
const Host &GetHost(void) const { return mDescription.mHost; }
const Host &GetHost(void) const { return *mDescription->mHost; }
/**
* This method returns the expire time (in milliseconds) of the service.
@@ -322,7 +327,7 @@ public:
*/
bool MatchesInstanceName(const char *aInstanceName) const
{
return (mDescription.mInstanceName == aInstanceName);
return (mDescription->mInstanceName == aInstanceName);
}
/**
@@ -337,12 +342,11 @@ public:
bool MatchesServiceName(const char *aServiceName) const { return (mServiceName == aServiceName); }
private:
struct Description : public LinkedListEntry<Description>, private NonCopyable
struct Description : public LinkedListEntry<Description>,
public Heap::Allocatable<Description>,
private NonCopyable
{
static Description *New(const char *aInstanceName, Host &aHost);
explicit Description(Host &aHost);
void Free(void);
Error Init(const char *aInstanceName, Host &aHost);
const char *GetInstanceName(void) const { return mInstanceName.AsCString(); }
bool Matches(const char *aInstanceName) const { return (mInstanceName == aInstanceName); }
void ClearResources(void);
@@ -351,7 +355,7 @@ public:
Description *mNext;
Heap::String mInstanceName;
Host & mHost;
Host * mHost;
Heap::Data mTxtData;
uint16_t mPriority;
uint16_t mWeight;
@@ -371,20 +375,13 @@ public:
kKeyLeaseExpired,
};
static Service *New(const char * aServiceName,
Description &aDescription,
bool aIsSubType,
TimeMilli aUpdateTime);
Service(Description &aDescription, bool aIsSubType, TimeMilli aUpdateTime);
void Free(void);
bool MatchesFlags(Flags aFlags) const;
Error Init(const char *aServiceName, Description &aDescription, bool aIsSubType, TimeMilli aUpdateTime);
bool MatchesFlags(Flags aFlags) const;
const TimeMilli &GetUpdateTime(void) const { return mUpdateTime; }
void Log(Action aAction) const;
Heap::String mServiceName;
Description &mDescription;
Description *mDescription;
Service * mNext;
TimeMilli mUpdateTime;
bool mIsDeleted : 1;
@@ -396,10 +393,15 @@ public:
* This class implements the Host which registers services on the SRP server.
*
*/
class Host : public otSrpServerHost, public LinkedListEntry<Host>, public InstanceLocator, private NonCopyable
class Host : public otSrpServerHost,
public InstanceLocatorInit,
public LinkedListEntry<Host>,
private Heap::Allocatable<Host>,
private NonCopyable
{
friend class LinkedListEntry<Host>;
friend class Server;
friend class LinkedListEntry<Host>;
friend class Heap::Allocatable<Host>;
public:
/**
@@ -513,10 +515,10 @@ public:
private:
static constexpr uint16_t kMaxAddresses = OPENTHREAD_CONFIG_SRP_SERVER_MAX_ADDRESSES_NUM;
static Host *New(Instance &aInstance, TimeMilli aUpdateTime);
Host(void) = default;
~Host(void);
Host(Instance &aInstance, TimeMilli aUpdateTime);
void Free(void);
Error Init(Instance &aInstance, TimeMilli aUpdateTime);
Error SetFullName(const char *aFullName);
void SetKey(Dns::Ecdsa256KeyRecord &aKey);
void SetLease(uint32_t aLease) { mLease = aLease; }
@@ -786,31 +788,33 @@ private:
// This class includes metadata for processing a SRP update (register, deregister)
// and sending DNS response to the client.
class UpdateMetadata : public InstanceLocator, public LinkedListEntry<UpdateMetadata>
class UpdateMetadata : public InstanceLocatorInit,
public LinkedListEntry<UpdateMetadata>,
public Heap::Allocatable<UpdateMetadata>
{
friend class LinkedListEntry<UpdateMetadata>;
friend class Heap::Allocatable<UpdateMetadata>;
public:
static UpdateMetadata * New(Instance &aInstance, Host &aHost, const MessageMetadata &aMessageMetadata);
void Free(void);
Error Init(Instance &aInstance, Host &aHost, const MessageMetadata &aMessageMetadata);
TimeMilli GetExpireTime(void) const { return mExpireTime; }
const Dns::UpdateHeader &GetDnsHeader(void) const { return mDnsHeader; }
ServiceUpdateId GetId(void) const { return mId; }
const LeaseConfig & GetLeaseConfig(void) const { return mLeaseConfig; }
Host & GetHost(void) { return mHost; }
Host & GetHost(void) { return *mHost; }
const Ip6::MessageInfo & GetMessageInfo(void) const { return mMessageInfo; }
bool IsDirectRxFromClient(void) const { return mIsDirectRxFromClient; }
bool Matches(ServiceUpdateId aId) const { return mId == aId; }
private:
UpdateMetadata(Instance &aInstance, Host &aHost, const MessageMetadata &aMessageMetadata);
UpdateMetadata(void) = default;
UpdateMetadata * mNext;
TimeMilli mExpireTime;
Dns::UpdateHeader mDnsHeader;
ServiceUpdateId mId; // The ID of this service update transaction.
LeaseConfig mLeaseConfig; // Lease config to use when processing the message.
Host & mHost; // The `UpdateMetadata` has no ownership of this host.
Host * mHost; // The `UpdateMetadata` has no ownership of this host.
Ip6::MessageInfo mMessageInfo; // Valid when `mIsDirectRxFromClient` is true.
bool mIsDirectRxFromClient;
};