[linked-list] adding LinkedList class (#4357)

This commit adds a linked list module which provides a template
implementation of a singly linked list. The new class is then used in
different core modules (netif (unicast/multicast addresses), UDP6
sockets/receiver, coap resources, etc). This commit also adds a
unit test `test_linked_list` for the linked list module.
This commit is contained in:
Abtin Keshavarzian
2019-12-04 11:03:52 -08:00
committed by Jonathan Hui
parent 15e26f0e64
commit e17c82b0b9
16 changed files with 604 additions and 345 deletions
+1
View File
@@ -310,6 +310,7 @@ HEADERS_COMMON = \
common/encoding.hpp \ common/encoding.hpp \
common/extension.hpp \ common/extension.hpp \
common/instance.hpp \ common/instance.hpp \
common/linked_list.hpp \
common/locator.hpp \ common/locator.hpp \
common/locator-getters.hpp \ common/locator-getters.hpp \
common/logging.hpp \ common/logging.hpp \
+5 -32
View File
@@ -49,7 +49,7 @@ namespace Coap {
CoapBase::CoapBase(Instance &aInstance, Sender aSender) CoapBase::CoapBase(Instance &aInstance, Sender aSender)
: InstanceLocator(aInstance) : InstanceLocator(aInstance)
, mRetransmissionTimer(aInstance, &Coap::HandleRetransmissionTimer, this) , mRetransmissionTimer(aInstance, &Coap::HandleRetransmissionTimer, this)
, mResources(NULL) , mResources()
, mContext(NULL) , mContext(NULL)
, mInterceptor(NULL) , mInterceptor(NULL)
, mResponsesQueue(aInstance) , mResponsesQueue(aInstance)
@@ -81,40 +81,13 @@ void CoapBase::ClearRequestsAndResponses(void)
otError CoapBase::AddResource(Resource &aResource) otError CoapBase::AddResource(Resource &aResource)
{ {
otError error = OT_ERROR_NONE; return mResources.Add(aResource);
for (Resource *cur = mResources; cur; cur = cur->GetNext())
{
VerifyOrExit(cur != &aResource, error = OT_ERROR_ALREADY);
}
aResource.mNext = mResources;
mResources = &aResource;
exit:
return error;
} }
void CoapBase::RemoveResource(Resource &aResource) void CoapBase::RemoveResource(Resource &aResource)
{ {
if (mResources == &aResource) mResources.Remove(aResource);
{ aResource.SetNext(NULL);
mResources = aResource.GetNext();
}
else
{
for (Resource *cur = mResources; cur; cur = cur->GetNext())
{
if (cur->mNext == &aResource)
{
cur->mNext = aResource.mNext;
ExitNow();
}
}
}
exit:
aResource.mNext = NULL;
} }
void CoapBase::SetDefaultHandler(otCoapRequestHandler aHandler, void *aContext) void CoapBase::SetDefaultHandler(otCoapRequestHandler aHandler, void *aContext)
@@ -611,7 +584,7 @@ void CoapBase::ProcessReceivedRequest(Message &aMessage, const Ip6::MessageInfo
curUriPath[0] = '\0'; curUriPath[0] = '\0';
for (const Resource *resource = mResources; resource; resource = resource->GetNext()) for (const Resource *resource = mResources.GetHead(); resource; resource = resource->GetNext())
{ {
if (strcmp(resource->mUriPath, uriPath) == 0) if (strcmp(resource->mUriPath, uriPath) == 0)
{ {
+3 -10
View File
@@ -35,6 +35,7 @@
#include "coap/coap_message.hpp" #include "coap/coap_message.hpp"
#include "common/debug.hpp" #include "common/debug.hpp"
#include "common/linked_list.hpp"
#include "common/locator.hpp" #include "common/locator.hpp"
#include "common/message.hpp" #include "common/message.hpp"
#include "common/timer.hpp" #include "common/timer.hpp"
@@ -175,7 +176,7 @@ private:
* This class implements CoAP resource handling. * This class implements CoAP resource handling.
* *
*/ */
class Resource : public otCoapResource class Resource : public otCoapResource, public LinkedListEntry<Resource>
{ {
friend class CoapBase; friend class CoapBase;
@@ -200,14 +201,6 @@ public:
mNext = NULL; mNext = NULL;
} }
/**
* This method returns a pointer to the next resource.
*
* @returns A pointer to the next resource.
*
*/
Resource *GetNext(void) const { return static_cast<Resource *>(mNext); }
/** /**
* This method returns a pointer to the Uri-Path. * This method returns a pointer to the Uri-Path.
* *
@@ -678,7 +671,7 @@ private:
uint16_t mMessageId; uint16_t mMessageId;
TimerMilliContext mRetransmissionTimer; TimerMilliContext mRetransmissionTimer;
Resource *mResources; LinkedList<Resource> mResources;
void * mContext; void * mContext;
Interceptor mInterceptor; Interceptor mInterceptor;
+317
View File
@@ -0,0 +1,317 @@
/*
* Copyright (c) 2019, 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 a generic singly linked list.
*/
#ifndef LINKED_LIST_HPP_
#define LINKED_LIST_HPP_
#include "openthread-core-config.h"
#include <stdio.h>
#include <openthread/error.h>
namespace ot {
/**
* @addtogroup core-linked-list
*
* @brief
* This module includes definitions for OpenThread Singly Linked List.
*
* @{
*
*/
/**
* This template class represents a linked list entry.
*
* This class provides methods to `GetNext()` and `SetNext()` in the linked list entry.
*
* Users of this class should follow CRTP-style inheritance, i.e., the `Type` class itself should publicly inherit
* from `LinkedListEntry<Type>`.
*
* The template type `Type` should contain a `mNext` member variable. The `mNext` should be of a type that can be
* down-casted to `Type` itself.
*
*/
template <class Type> class LinkedListEntry
{
public:
/**
* This method gets the next entry in the linked list.
*
* @returns A pointer to the next entry in the linked list or NULL if at the end of the list.
*
*/
const Type *GetNext(void) const { return static_cast<const Type *>(static_cast<const Type *>(this)->mNext); }
/**
* This method gets the next entry in the linked list.
*
* @returns A pointer to the next entry in the linked list or NULL if at the end of the list.
*
*/
Type *GetNext(void) { return static_cast<Type *>(static_cast<Type *>(this)->mNext); }
/**
* This method sets the next pointer on the entry.
*
* @param[in] aNext A pointer to the next entry.
*
*/
void SetNext(Type *aNext) { static_cast<Type *>(this)->mNext = aNext; }
};
/**
* This template class represents a singly linked list.
*
* The template type `Type` should provide `GetNext()` and `SetNext()` methods (which can be realized by `Type`
* inheriting from `LinkedListEntry<Type>` class).
*
*/
template <typename Type> class LinkedList
{
public:
/**
* This constructor initializes the linked list.
*
*/
LinkedList(void)
: mHead(NULL)
{
}
/**
* This method returns the entry at the head of the linked list
*
* @returns Pointer to the entry at the head of the linked list, or NULL if list is empty.
*
*/
Type *GetHead(void) { return mHead; }
/**
* This method returns the entry at the head of the linked list.
*
* @returns Pointer to the entry at the head of the linked list, or NULL if list is empty.
*
*/
const Type *GetHead(void) const { return mHead; }
/**
* This method sets the head of the linked list to a given entry.
*
* @param[in] aHead A pointer to an entry to set as the head of the linked list.
*
*/
void SetHead(Type *aHead) { mHead = aHead; }
/**
* This method clears the linked list.
*
*/
void Clear(void) { mHead = NULL; }
/**
* This method indicates whether the linked list is empty or not.
*
* @retval TRUE If the linked list is empty.
* @retval FALSE If the linked list is not empty.
*
*/
bool IsEmpty(void) const { return (mHead == NULL); }
/**
* This method pushes an entry at the head of the linked list.
*
* @param[in] aEntry A reference to an entry to push at the head of linked list.
*
*/
void Push(Type &aEntry)
{
aEntry.SetNext(mHead);
mHead = &aEntry;
}
/**
* This method pushes an entry after a given previous existing entry in the linked list.
*
* @param[in] aEntry A reference to an entry to push into the list.
* @param[in] aPrevEntry A reference to a previous entry (new entry @p aEntry will be pushed after this).
*
*/
void PushAfter(Type &aEntry, Type &aPrevEntry)
{
aEntry.SetNext(aPrevEntry.GetNext());
aPrevEntry.SetNext(&aEntry);
}
/**
* This method pops an entry from head of the linked list.
*
* @note This method does not change the popped entry itself, i.e., the popped entry next pointer stays as before.
*
* @returns The entry that was popped if list is not empty, or NULL if list is empty.
*
*/
Type *Pop(void)
{
Type *entry = mHead;
if (mHead != NULL)
{
mHead = mHead->GetNext();
}
return entry;
}
/**
* This method pops an entry after a given previous entry.
*
* @note This method does not change the popped entry itself, i.e., the popped entry next pointer stays as before.
*
* @param[in] aPrevEntry A reference to n previous entry (the entry after this will be popped).
* @returns The entry that was popped if list is not empty, or NULL if there is no entry after the given one.
*
*/
Type *PopAfter(Type &aPrevEntry)
{
Type *entry = aPrevEntry.GetNext();
if (entry != NULL)
{
aPrevEntry.SetNext(entry->GetNext());
}
return entry;
}
/**
* This method indicates whether the linked list contains a given entry.
*
* @param[in] aEntry A reference to an entry.
*
* @retval TRUE The linked list contains @p aEntry.
* @retval FALSE The linked list does not contain @p aEntry.
*
*/
bool Contains(Type &aEntry) const
{
bool contains = false;
for (Type *cur = mHead; cur != NULL; cur = cur->GetNext())
{
if (cur == &aEntry)
{
contains = true;
break;
}
}
return contains;
}
/**
* This method adds an entry (at the head of the linked list) if it is not already in the list.
*
* @param[in] aEntry A reference to an entry to add.
*
* @retval OT_ERROR_NONE The entry was successfully added at the head of the list.
* @retval OT_ERROR_ALREADY The entry is already in the list.
*
*/
otError Add(Type &aEntry)
{
otError error = OT_ERROR_NONE;
if (Contains(aEntry))
{
error = OT_ERROR_ALREADY;
}
else
{
Push(aEntry);
}
return error;
}
/**
* This method removes an entry from the linked list.
*
* @note This method does not change the removed entry @p aEntry itself (it is `const`), i.e., the entry next
* pointer of @p aEntry stays as before.
*
* @param[in] aEntry A reference to an entry to remove.
*
* @retval OT_ERROR_NONE The entry was successfully removed from the list.
* @retval OT_ERROR_NOT_FOUND Could not find the entry in the list.
*
*/
otError Remove(const Type &aEntry)
{
otError error = OT_ERROR_NOT_FOUND;
if (mHead == &aEntry)
{
Pop();
error = OT_ERROR_NONE;
}
else if (mHead != NULL)
{
for (Type *cur = mHead; cur->GetNext() != NULL; cur = cur->GetNext())
{
if (cur->GetNext() == &aEntry)
{
cur->SetNext(cur->GetNext()->GetNext());
error = OT_ERROR_NONE;
break;
}
}
}
return error;
}
private:
Type *mHead;
};
/**
* @}
*
*/
} // namespace ot
#endif // LINKED_LIST_HPP_
+3 -4
View File
@@ -54,7 +54,7 @@ Notifier::Notifier(Instance &aInstance)
, mFlagsToSignal(0) , mFlagsToSignal(0)
, mSignaledFlags(0) , mSignaledFlags(0)
, mTask(aInstance, &Notifier::HandleStateChanged, this) , mTask(aInstance, &Notifier::HandleStateChanged, this)
, mCallbacks(NULL) , mCallbacks()
{ {
for (unsigned int i = 0; i < kMaxExternalHandlers; i++) for (unsigned int i = 0; i < kMaxExternalHandlers; i++)
{ {
@@ -65,8 +65,7 @@ Notifier::Notifier(Instance &aInstance)
void Notifier::RegisterCallback(Callback &aCallback) void Notifier::RegisterCallback(Callback &aCallback)
{ {
aCallback.mNext = mCallbacks; mCallbacks.Push(aCallback);
mCallbacks = &aCallback;
} }
otError Notifier::RegisterCallback(otStateChangedCallback aCallback, void *aContext) otError Notifier::RegisterCallback(otStateChangedCallback aCallback, void *aContext)
@@ -151,7 +150,7 @@ void Notifier::HandleStateChanged(void)
LogChangedFlags(flags); LogChangedFlags(flags);
for (Callback *callback = mCallbacks; callback != NULL; callback = callback->mNext) for (Callback *callback = mCallbacks.GetHead(); callback != NULL; callback = callback->GetNext())
{ {
callback->Invoke(flags); callback->Invoke(flags);
} }
+8 -6
View File
@@ -42,6 +42,7 @@
#include <openthread/instance.h> #include <openthread/instance.h>
#include <openthread/platform/toolchain.h> #include <openthread/platform/toolchain.h>
#include "common/linked_list.hpp"
#include "common/locator.hpp" #include "common/locator.hpp"
#include "common/tasklet.hpp" #include "common/tasklet.hpp"
@@ -79,9 +80,10 @@ public:
* This class defines a `Notifier` callback instance. * This class defines a `Notifier` callback instance.
* *
*/ */
class Callback : public OwnerLocator class Callback : public OwnerLocator, public LinkedListEntry<Callback>
{ {
friend class Notifier; friend class Notifier;
friend class LinkedListEntry<Callback>;
public: public:
/** /**
@@ -232,11 +234,11 @@ private:
void LogChangedFlags(otChangedFlags aFlags) const; void LogChangedFlags(otChangedFlags aFlags) const;
const char *FlagToString(otChangedFlags aFlag) const; const char *FlagToString(otChangedFlags aFlag) const;
otChangedFlags mFlagsToSignal; otChangedFlags mFlagsToSignal;
otChangedFlags mSignaledFlags; otChangedFlags mSignaledFlags;
Tasklet mTask; Tasklet mTask;
Callback * mCallbacks; LinkedList<Callback> mCallbacks;
ExternalCallback mExternalCallbacks[kMaxExternalHandlers]; ExternalCallback mExternalCallbacks[kMaxExternalHandlers];
}; };
/** /**
+23 -50
View File
@@ -100,73 +100,45 @@ void TimerMilli::Stop(void)
void TimerScheduler::Add(Timer &aTimer, const AlarmApi &aAlarmApi) void TimerScheduler::Add(Timer &aTimer, const AlarmApi &aAlarmApi)
{ {
Timer *prev = NULL;
Time now(aAlarmApi.AlarmGetNow());
Remove(aTimer, aAlarmApi); Remove(aTimer, aAlarmApi);
if (mHead == NULL) for (Timer *cur = mTimerList.GetHead(); cur; prev = cur, cur = cur->GetNext())
{ {
mHead = &aTimer; if (aTimer.DoesFireBefore(*cur, now))
aTimer.mNext = NULL; {
break;
}
}
if (prev == NULL)
{
mTimerList.Push(aTimer);
SetAlarm(aAlarmApi); SetAlarm(aAlarmApi);
} }
else else
{ {
Timer *prev = NULL; mTimerList.PushAfter(aTimer, *prev);
Timer *cur;
for (cur = mHead; cur; cur = cur->mNext)
{
Time now(aAlarmApi.AlarmGetNow());
if (aTimer.DoesFireBefore(*cur, now))
{
if (prev)
{
aTimer.mNext = cur;
prev->mNext = &aTimer;
}
else
{
aTimer.mNext = mHead;
mHead = &aTimer;
SetAlarm(aAlarmApi);
}
break;
}
prev = cur;
}
if (cur == NULL)
{
prev->mNext = &aTimer;
aTimer.mNext = NULL;
}
} }
} }
void TimerScheduler::Remove(Timer &aTimer, const AlarmApi &aAlarmApi) void TimerScheduler::Remove(Timer &aTimer, const AlarmApi &aAlarmApi)
{ {
VerifyOrExit(aTimer.mNext != &aTimer); VerifyOrExit(aTimer.IsRunning());
if (mHead == &aTimer) if (mTimerList.GetHead() == &aTimer)
{ {
mHead = aTimer.mNext; mTimerList.Pop();
SetAlarm(aAlarmApi); SetAlarm(aAlarmApi);
} }
else else
{ {
for (Timer *cur = mHead; cur; cur = cur->mNext) mTimerList.Remove(aTimer);
{
if (cur->mNext == &aTimer)
{
cur->mNext = aTimer.mNext;
break;
}
}
} }
aTimer.mNext = &aTimer; aTimer.SetNext(&aTimer);
exit: exit:
return; return;
@@ -174,16 +146,17 @@ exit:
void TimerScheduler::SetAlarm(const AlarmApi &aAlarmApi) void TimerScheduler::SetAlarm(const AlarmApi &aAlarmApi)
{ {
if (mHead == NULL) if (mTimerList.IsEmpty())
{ {
aAlarmApi.AlarmStop(&GetInstance()); aAlarmApi.AlarmStop(&GetInstance());
} }
else else
{ {
Timer * timer = mTimerList.GetHead();
Time now(aAlarmApi.AlarmGetNow()); Time now(aAlarmApi.AlarmGetNow());
uint32_t remaining; uint32_t remaining;
remaining = (now < mHead->mFireTime) ? (mHead->mFireTime - now) : 0; remaining = (now < timer->mFireTime) ? (timer->mFireTime - now) : 0;
aAlarmApi.AlarmStartAt(&GetInstance(), now.GetValue(), remaining); aAlarmApi.AlarmStartAt(&GetInstance(), now.GetValue(), remaining);
} }
@@ -191,7 +164,7 @@ void TimerScheduler::SetAlarm(const AlarmApi &aAlarmApi)
void TimerScheduler::ProcessTimers(const AlarmApi &aAlarmApi) void TimerScheduler::ProcessTimers(const AlarmApi &aAlarmApi)
{ {
Timer *timer = mHead; Timer *timer = mTimerList.GetHead();
if (timer) if (timer)
{ {
+5 -3
View File
@@ -43,6 +43,7 @@
#include <openthread/platform/alarm-milli.h> #include <openthread/platform/alarm-milli.h>
#include "common/debug.hpp" #include "common/debug.hpp"
#include "common/linked_list.hpp"
#include "common/locator.hpp" #include "common/locator.hpp"
#include "common/tasklet.hpp" #include "common/tasklet.hpp"
#include "common/time.hpp" #include "common/time.hpp"
@@ -65,9 +66,10 @@ class TimerMilliScheduler;
* This class implements a timer. * This class implements a timer.
* *
*/ */
class Timer : public InstanceLocator, public OwnerLocator class Timer : public InstanceLocator, public OwnerLocator, public LinkedListEntry<Timer>
{ {
friend class TimerScheduler; friend class TimerScheduler;
friend class LinkedListEntry<Timer>;
public: public:
/** /**
@@ -273,7 +275,7 @@ protected:
*/ */
explicit TimerScheduler(Instance &aInstance) explicit TimerScheduler(Instance &aInstance)
: InstanceLocator(aInstance) : InstanceLocator(aInstance)
, mHead(NULL) , mTimerList()
{ {
} }
@@ -311,7 +313,7 @@ protected:
*/ */
void SetAlarm(const AlarmApi &aAlarmApi); void SetAlarm(const AlarmApi &aAlarmApi);
Timer *mHead; LinkedList<Timer> mTimerList;
}; };
/** /**
+3 -17
View File
@@ -50,7 +50,7 @@ namespace Ip6 {
Icmp::Icmp(Instance &aInstance) Icmp::Icmp(Instance &aInstance)
: InstanceLocator(aInstance) : InstanceLocator(aInstance)
, mHandlers(NULL) , mHandlers()
, mEchoSequence(1) , mEchoSequence(1)
, mEchoMode(OT_ICMP6_ECHO_HANDLER_ALL) , mEchoMode(OT_ICMP6_ECHO_HANDLER_ALL)
{ {
@@ -63,21 +63,7 @@ Message *Icmp::NewMessage(uint16_t aReserved)
otError Icmp::RegisterHandler(IcmpHandler &aHandler) otError Icmp::RegisterHandler(IcmpHandler &aHandler)
{ {
otError error = OT_ERROR_NONE; return mHandlers.Add(aHandler);
for (IcmpHandler *cur = mHandlers; cur; cur = cur->GetNext())
{
if (cur == &aHandler)
{
ExitNow(error = OT_ERROR_ALREADY);
}
}
aHandler.mNext = mHandlers;
mHandlers = &aHandler;
exit:
return error;
} }
otError Icmp::SendEchoRequest(Message &aMessage, const MessageInfo &aMessageInfo, uint16_t aIdentifier) otError Icmp::SendEchoRequest(Message &aMessage, const MessageInfo &aMessageInfo, uint16_t aIdentifier)
@@ -163,7 +149,7 @@ otError Icmp::HandleMessage(Message &aMessage, MessageInfo &aMessageInfo)
aMessage.MoveOffset(sizeof(icmp6Header)); aMessage.MoveOffset(sizeof(icmp6Header));
for (IcmpHandler *handler = mHandlers; handler; handler = handler->GetNext()) for (IcmpHandler *handler = mHandlers.GetHead(); handler; handler = handler->GetNext())
{ {
handler->HandleReceiveMessage(aMessage, aMessageInfo, icmp6Header); handler->HandleReceiveMessage(aMessage, aMessageInfo, icmp6Header);
} }
+3 -4
View File
@@ -39,6 +39,7 @@
#include <openthread/icmp6.h> #include <openthread/icmp6.h>
#include "common/encoding.hpp" #include "common/encoding.hpp"
#include "common/linked_list.hpp"
#include "common/locator.hpp" #include "common/locator.hpp"
#include "net/ip6_headers.hpp" #include "net/ip6_headers.hpp"
@@ -201,7 +202,7 @@ public:
* This class implements ICMPv6 message handlers. * This class implements ICMPv6 message handlers.
* *
*/ */
class IcmpHandler : public otIcmp6Handler class IcmpHandler : public otIcmp6Handler, public LinkedListEntry<IcmpHandler>
{ {
friend class Icmp; friend class Icmp;
@@ -225,8 +226,6 @@ private:
{ {
mReceiveCallback(mContext, &aMessage, &aMessageInfo, &aIcmp6Header); mReceiveCallback(mContext, &aMessage, &aMessageInfo, &aIcmp6Header);
} }
IcmpHandler *GetNext(void) { return static_cast<IcmpHandler *>(mNext); }
}; };
/** /**
@@ -347,7 +346,7 @@ public:
private: private:
otError HandleEchoRequest(Message &aRequestMessage, const MessageInfo &aMessageInfo); otError HandleEchoRequest(Message &aRequestMessage, const MessageInfo &aMessageInfo);
IcmpHandler *mHandlers; LinkedList<IcmpHandler> mHandlers;
uint16_t mEchoSequence; uint16_t mEchoSequence;
otIcmp6EchoMode mEchoMode; otIcmp6EchoMode mEchoMode;
+45 -107
View File
@@ -82,8 +82,8 @@ const otNetifMulticastAddress Netif::kLinkLocalAllRoutersMulticastAddress = {
Netif::Netif(Instance &aInstance) Netif::Netif(Instance &aInstance)
: InstanceLocator(aInstance) : InstanceLocator(aInstance)
, mUnicastAddresses(NULL) , mUnicastAddresses()
, mMulticastAddresses(NULL) , mMulticastAddresses()
, mMulticastPromiscuous(false) , mMulticastPromiscuous(false)
, mNext(NULL) , mNext(NULL)
, mAddressCallback(NULL) , mAddressCallback(NULL)
@@ -107,7 +107,7 @@ bool Netif::IsMulticastSubscribed(const Address &aAddress) const
{ {
bool rval = false; bool rval = false;
for (NetifMulticastAddress *cur = mMulticastAddresses; cur; cur = cur->GetNext()) for (const NetifMulticastAddress *cur = mMulticastAddresses.GetHead(); cur; cur = cur->GetNext())
{ {
if (cur->GetAddress() == aAddress) if (cur->GetAddress() == aAddress)
{ {
@@ -121,10 +121,10 @@ exit:
void Netif::SubscribeAllNodesMulticast(void) void Netif::SubscribeAllNodesMulticast(void)
{ {
assert(mMulticastAddresses == NULL); assert(mMulticastAddresses.IsEmpty());
mMulticastAddresses = static_cast<NetifMulticastAddress *>( mMulticastAddresses.SetHead(static_cast<NetifMulticastAddress *>(
const_cast<otNetifMulticastAddress *>(&kLinkLocalAllNodesMulticastAddress)); const_cast<otNetifMulticastAddress *>(&kLinkLocalAllNodesMulticastAddress)));
if (mAddressCallback != NULL) if (mAddressCallback != NULL)
{ {
@@ -140,9 +140,9 @@ void Netif::SubscribeAllNodesMulticast(void)
void Netif::UnsubscribeAllNodesMulticast(void) void Netif::UnsubscribeAllNodesMulticast(void)
{ {
assert(mMulticastAddresses == NULL || mMulticastAddresses == &kLinkLocalAllNodesMulticastAddress); assert(mMulticastAddresses.IsEmpty() || mMulticastAddresses.GetHead() == &kLinkLocalAllNodesMulticastAddress);
mMulticastAddresses = NULL; mMulticastAddresses.SetHead(NULL);
if (mAddressCallback != NULL) if (mAddressCallback != NULL)
{ {
@@ -160,14 +160,14 @@ otError Netif::SubscribeAllRoutersMulticast(void)
{ {
otError error = OT_ERROR_NONE; otError error = OT_ERROR_NONE;
if (mMulticastAddresses == &kLinkLocalAllNodesMulticastAddress) if (mMulticastAddresses.GetHead() == &kLinkLocalAllNodesMulticastAddress)
{ {
mMulticastAddresses = static_cast<NetifMulticastAddress *>( mMulticastAddresses.SetHead(static_cast<NetifMulticastAddress *>(
const_cast<otNetifMulticastAddress *>(&kLinkLocalAllRoutersMulticastAddress)); const_cast<otNetifMulticastAddress *>(&kLinkLocalAllRoutersMulticastAddress)));
} }
else else
{ {
for (NetifMulticastAddress *cur = mMulticastAddresses; cur; cur = cur->GetNext()) for (NetifMulticastAddress *cur = mMulticastAddresses.GetHead(); cur; cur = cur->GetNext())
{ {
if (cur == &kLinkLocalAllRoutersMulticastAddress) if (cur == &kLinkLocalAllRoutersMulticastAddress)
{ {
@@ -201,14 +201,14 @@ otError Netif::UnsubscribeAllRoutersMulticast(void)
{ {
otError error = OT_ERROR_NONE; otError error = OT_ERROR_NONE;
if (mMulticastAddresses == &kLinkLocalAllRoutersMulticastAddress) if (mMulticastAddresses.GetHead() == &kLinkLocalAllRoutersMulticastAddress)
{ {
mMulticastAddresses = static_cast<NetifMulticastAddress *>( mMulticastAddresses.SetHead(static_cast<NetifMulticastAddress *>(
const_cast<otNetifMulticastAddress *>(&kLinkLocalAllNodesMulticastAddress)); const_cast<otNetifMulticastAddress *>(&kLinkLocalAllNodesMulticastAddress)));
ExitNow(); ExitNow();
} }
for (NetifMulticastAddress *cur = mMulticastAddresses; cur; cur = cur->GetNext()) for (NetifMulticastAddress *cur = mMulticastAddresses.GetHead(); cur; cur = cur->GetNext())
{ {
if (cur->mNext == &kLinkLocalAllRoutersMulticastAddress) if (cur->mNext == &kLinkLocalAllRoutersMulticastAddress)
{ {
@@ -240,18 +240,9 @@ exit:
otError Netif::SubscribeMulticast(NetifMulticastAddress &aAddress) otError Netif::SubscribeMulticast(NetifMulticastAddress &aAddress)
{ {
otError error = OT_ERROR_NONE; otError error;
for (NetifMulticastAddress *cur = mMulticastAddresses; cur; cur = cur->GetNext()) SuccessOrExit(error = mMulticastAddresses.Add(aAddress));
{
if (cur == &aAddress)
{
ExitNow(error = OT_ERROR_ALREADY);
}
}
aAddress.mNext = mMulticastAddresses;
mMulticastAddresses = &aAddress;
if (mAddressCallback != NULL) if (mAddressCallback != NULL)
{ {
@@ -266,39 +257,18 @@ exit:
otError Netif::UnsubscribeMulticast(const NetifMulticastAddress &aAddress) otError Netif::UnsubscribeMulticast(const NetifMulticastAddress &aAddress)
{ {
otError error = OT_ERROR_NONE; otError error;
if (mMulticastAddresses == &aAddress) SuccessOrExit(error = mMulticastAddresses.Remove(aAddress));
if (mAddressCallback != NULL)
{ {
mMulticastAddresses = mMulticastAddresses->GetNext(); mAddressCallback(&aAddress.mAddress, kMulticastPrefixLength, false, mAddressCallbackContext);
ExitNow();
}
else if (mMulticastAddresses != NULL)
{
for (NetifMulticastAddress *cur = mMulticastAddresses; cur->GetNext(); cur = cur->GetNext())
{
if (cur->mNext == &aAddress)
{
cur->mNext = aAddress.mNext;
ExitNow();
}
}
} }
ExitNow(error = OT_ERROR_NOT_FOUND); Get<Notifier>().Signal(OT_CHANGED_IP6_MULTICAST_UNSUBSCRIBED);
exit: exit:
if (error != OT_ERROR_NOT_FOUND)
{
if (mAddressCallback != NULL)
{
mAddressCallback(&aAddress.mAddress, kMulticastPrefixLength, false, mAddressCallbackContext);
}
Get<Notifier>().Signal(OT_CHANGED_IP6_MULTICAST_UNSUBSCRIBED);
}
return error; return error;
} }
@@ -332,7 +302,7 @@ otError Netif::SubscribeExternalMulticast(const Address &aAddress)
otError error = OT_ERROR_NONE; otError error = OT_ERROR_NONE;
NetifMulticastAddress *entry; NetifMulticastAddress *entry;
VerifyOrExit(mMulticastAddresses != NULL, error = OT_ERROR_INVALID_STATE); VerifyOrExit(!mMulticastAddresses.IsEmpty(), error = OT_ERROR_INVALID_STATE);
if (IsMulticastSubscribed(aAddress)) if (IsMulticastSubscribed(aAddress))
{ {
@@ -352,9 +322,8 @@ otError Netif::SubscribeExternalMulticast(const Address &aAddress)
VerifyOrExit(entry < OT_ARRAY_END(mExtMulticastAddresses), error = OT_ERROR_NO_BUFS); VerifyOrExit(entry < OT_ARRAY_END(mExtMulticastAddresses), error = OT_ERROR_NO_BUFS);
// Copy the address into the available entry and add it to linked-list. // Copy the address into the available entry and add it to linked-list.
entry->mAddress = aAddress; entry->mAddress = aAddress;
entry->mNext = mMulticastAddresses; mMulticastAddresses.Push(*entry);
mMulticastAddresses = entry;
Get<Notifier>().Signal(OT_CHANGED_IP6_MULTICAST_SUBSCRIBED); Get<Notifier>().Signal(OT_CHANGED_IP6_MULTICAST_SUBSCRIBED);
exit: exit:
@@ -367,7 +336,7 @@ otError Netif::UnsubscribeExternalMulticast(const Address &aAddress)
NetifMulticastAddress *entry; NetifMulticastAddress *entry;
NetifMulticastAddress *last = NULL; NetifMulticastAddress *last = NULL;
for (entry = mMulticastAddresses; entry; entry = entry->GetNext()) for (entry = mMulticastAddresses.GetHead(); entry; entry = entry->GetNext())
{ {
if (entry->GetAddress() == aAddress) if (entry->GetAddress() == aAddress)
{ {
@@ -376,11 +345,11 @@ otError Netif::UnsubscribeExternalMulticast(const Address &aAddress)
if (last) if (last)
{ {
last->mNext = entry->GetNext(); mMulticastAddresses.PopAfter(*last);
} }
else else
{ {
mMulticastAddresses = entry->GetNext(); mMulticastAddresses.Pop();
} }
break; break;
@@ -421,18 +390,9 @@ void Netif::SetAddressCallback(otIp6AddressCallback aCallback, void *aCallbackCo
otError Netif::AddUnicastAddress(NetifUnicastAddress &aAddress) otError Netif::AddUnicastAddress(NetifUnicastAddress &aAddress)
{ {
otError error = OT_ERROR_NONE; otError error;
for (NetifUnicastAddress *cur = mUnicastAddresses; cur; cur = cur->GetNext()) SuccessOrExit(error = mUnicastAddresses.Add(aAddress));
{
if (cur == &aAddress)
{
ExitNow(error = OT_ERROR_ALREADY);
}
}
aAddress.mNext = mUnicastAddresses;
mUnicastAddresses = &aAddress;
if (mAddressCallback != NULL) if (mAddressCallback != NULL)
{ {
@@ -447,39 +407,18 @@ exit:
otError Netif::RemoveUnicastAddress(const NetifUnicastAddress &aAddress) otError Netif::RemoveUnicastAddress(const NetifUnicastAddress &aAddress)
{ {
otError error = OT_ERROR_NONE; otError error;
if (mUnicastAddresses == &aAddress) SuccessOrExit(error = mUnicastAddresses.Remove(aAddress));
if (mAddressCallback != NULL)
{ {
mUnicastAddresses = mUnicastAddresses->GetNext(); mAddressCallback(&aAddress.mAddress, aAddress.mPrefixLength, false, mAddressCallbackContext);
ExitNow();
}
else if (mUnicastAddresses != NULL)
{
for (NetifUnicastAddress *cur = mUnicastAddresses; cur->GetNext(); cur = cur->GetNext())
{
if (cur->mNext == &aAddress)
{
cur->mNext = aAddress.mNext;
ExitNow();
}
}
} }
ExitNow(error = OT_ERROR_NOT_FOUND); Get<Notifier>().Signal(aAddress.mRloc ? OT_CHANGED_THREAD_RLOC_REMOVED : OT_CHANGED_IP6_ADDRESS_REMOVED);
exit: exit:
if (error != OT_ERROR_NOT_FOUND)
{
if (mAddressCallback != NULL)
{
mAddressCallback(&aAddress.mAddress, aAddress.mPrefixLength, false, mAddressCallbackContext);
}
Get<Notifier>().Signal(aAddress.mRloc ? OT_CHANGED_THREAD_RLOC_REMOVED : OT_CHANGED_IP6_ADDRESS_REMOVED);
}
return error; return error;
} }
@@ -490,7 +429,7 @@ otError Netif::AddExternalUnicastAddress(const NetifUnicastAddress &aAddress)
VerifyOrExit(!aAddress.GetAddress().IsLinkLocal(), error = OT_ERROR_INVALID_ARGS); VerifyOrExit(!aAddress.GetAddress().IsLinkLocal(), error = OT_ERROR_INVALID_ARGS);
for (entry = mUnicastAddresses; entry; entry = entry->GetNext()) for (entry = mUnicastAddresses.GetHead(); entry; entry = entry->GetNext())
{ {
if (entry->GetAddress() == aAddress.GetAddress()) if (entry->GetAddress() == aAddress.GetAddress())
{ {
@@ -517,9 +456,8 @@ otError Netif::AddExternalUnicastAddress(const NetifUnicastAddress &aAddress)
VerifyOrExit(entry < OT_ARRAY_END(mExtUnicastAddresses), error = OT_ERROR_NO_BUFS); VerifyOrExit(entry < OT_ARRAY_END(mExtUnicastAddresses), error = OT_ERROR_NO_BUFS);
// Copy the new address into the available entry and insert it in linked-list. // Copy the new address into the available entry and insert it in linked-list.
*entry = aAddress; *entry = aAddress;
entry->mNext = mUnicastAddresses; mUnicastAddresses.Push(*entry);
mUnicastAddresses = entry;
Get<Notifier>().Signal(OT_CHANGED_IP6_ADDRESS_ADDED); Get<Notifier>().Signal(OT_CHANGED_IP6_ADDRESS_ADDED);
@@ -533,7 +471,7 @@ otError Netif::RemoveExternalUnicastAddress(const Address &aAddress)
NetifUnicastAddress *entry; NetifUnicastAddress *entry;
NetifUnicastAddress *last = NULL; NetifUnicastAddress *last = NULL;
for (entry = mUnicastAddresses; entry; entry = entry->GetNext()) for (entry = mUnicastAddresses.GetHead(); entry; entry = entry->GetNext())
{ {
if (entry->GetAddress() == aAddress) if (entry->GetAddress() == aAddress)
{ {
@@ -542,11 +480,11 @@ otError Netif::RemoveExternalUnicastAddress(const Address &aAddress)
if (last) if (last)
{ {
last->mNext = entry->mNext; mUnicastAddresses.PopAfter(*last);
} }
else else
{ {
mUnicastAddresses = entry->GetNext(); mUnicastAddresses.Pop();
} }
break; break;
@@ -582,7 +520,7 @@ bool Netif::IsUnicastAddress(const Address &aAddress) const
{ {
bool rval = false; bool rval = false;
for (const NetifUnicastAddress *cur = mUnicastAddresses; cur; cur = cur->GetNext()) for (const NetifUnicastAddress *cur = mUnicastAddresses.GetHead(); cur; cur = cur->GetNext())
{ {
if (cur->GetAddress() == aAddress) if (cur->GetAddress() == aAddress)
{ {
+10 -32
View File
@@ -36,6 +36,7 @@
#include "openthread-core-config.h" #include "openthread-core-config.h"
#include "common/linked_list.hpp"
#include "common/locator.hpp" #include "common/locator.hpp"
#include "common/message.hpp" #include "common/message.hpp"
#include "common/tasklet.hpp" #include "common/tasklet.hpp"
@@ -62,7 +63,7 @@ class Ip6;
* This class implements an IPv6 network interface unicast address. * This class implements an IPv6 network interface unicast address.
* *
*/ */
class NetifUnicastAddress : public otNetifAddress class NetifUnicastAddress : public otNetifAddress, public LinkedListEntry<NetifUnicastAddress>
{ {
friend class Netif; friend class Netif;
@@ -93,29 +94,13 @@ public:
{ {
return mScopeOverrideValid ? static_cast<uint8_t>(mScopeOverride) : GetAddress().GetScope(); return mScopeOverrideValid ? static_cast<uint8_t>(mScopeOverride) : GetAddress().GetScope();
} }
/**
* This method returns the next unicast address assigned to the interface.
*
* @returns A pointer to the next unicast address.
*
*/
const NetifUnicastAddress *GetNext(void) const { return static_cast<const NetifUnicastAddress *>(mNext); }
/**
* This method returns the next unicast address assigned to the interface.
*
* @returns A pointer to the next unicast address.
*
*/
NetifUnicastAddress *GetNext(void) { return static_cast<NetifUnicastAddress *>(mNext); }
}; };
/** /**
* This class implements an IPv6 network interface multicast address. * This class implements an IPv6 network interface multicast address.
* *
*/ */
class NetifMulticastAddress : public otNetifMulticastAddress class NetifMulticastAddress : public otNetifMulticastAddress, public LinkedListEntry<NetifMulticastAddress>
{ {
friend class Netif; friend class Netif;
@@ -160,7 +145,7 @@ public:
* This class implements an IPv6 network interface. * This class implements an IPv6 network interface.
* *
*/ */
class Netif : public InstanceLocator class Netif : public InstanceLocator, public LinkedListEntry<Netif>
{ {
friend class Ip6; friend class Ip6;
@@ -173,13 +158,6 @@ public:
*/ */
Netif(Instance &aInstance); Netif(Instance &aInstance);
/**
* This method returns the next network interface in the list.
*
* @returns A pointer to the next network interface.
*/
Netif *GetNext(void) const { return mNext; }
/** /**
* This method registers a callback to notify internal IPv6 address changes. * This method registers a callback to notify internal IPv6 address changes.
* *
@@ -195,7 +173,7 @@ public:
* @returns A pointer to the list of unicast addresses. * @returns A pointer to the list of unicast addresses.
* *
*/ */
const NetifUnicastAddress *GetUnicastAddresses(void) const { return mUnicastAddresses; } const NetifUnicastAddress *GetUnicastAddresses(void) const { return mUnicastAddresses.GetHead(); }
/** /**
* This method adds a unicast address to the network interface. * This method adds a unicast address to the network interface.
@@ -295,7 +273,7 @@ public:
* @returns A pointer to the list of multicast addresses. * @returns A pointer to the list of multicast addresses.
* *
*/ */
const NetifMulticastAddress *GetMulticastAddresses(void) const { return mMulticastAddresses; } const NetifMulticastAddress *GetMulticastAddresses(void) const { return mMulticastAddresses.GetHead(); }
/** /**
* This method subscribes the network interface to a multicast address. * This method subscribes the network interface to a multicast address.
@@ -402,10 +380,10 @@ private:
kMulticastPrefixLength = 128, ///< Multicast prefix length used to notify internal address changes. kMulticastPrefixLength = 128, ///< Multicast prefix length used to notify internal address changes.
}; };
NetifUnicastAddress * mUnicastAddresses; LinkedList<NetifUnicastAddress> mUnicastAddresses;
NetifMulticastAddress *mMulticastAddresses; LinkedList<NetifMulticastAddress> mMulticastAddresses;
bool mMulticastPromiscuous; bool mMulticastPromiscuous;
Netif * mNext; Netif * mNext;
otIp6AddressCallback mAddressCallback; otIp6AddressCallback mAddressCallback;
void * mAddressCallbackContext; void * mAddressCallbackContext;
+14 -68
View File
@@ -205,8 +205,8 @@ exit:
Udp::Udp(Instance &aInstance) Udp::Udp(Instance &aInstance)
: InstanceLocator(aInstance) : InstanceLocator(aInstance)
, mEphemeralPort(kDynamicPortMin) , mEphemeralPort(kDynamicPortMin)
, mReceivers(NULL) , mReceivers()
, mSockets(NULL) , mSockets()
#if OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE #if OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE
, mUdpForwarderContext(NULL) , mUdpForwarderContext(NULL)
, mUdpForwarder(NULL) , mUdpForwarder(NULL)
@@ -216,86 +216,32 @@ Udp::Udp(Instance &aInstance)
otError Udp::AddReceiver(UdpReceiver &aReceiver) otError Udp::AddReceiver(UdpReceiver &aReceiver)
{ {
otError error = OT_ERROR_NONE; return mReceivers.Add(aReceiver);
for (UdpReceiver *cur = mReceivers; cur; cur = cur->GetNext())
{
if (cur == &aReceiver)
{
ExitNow(error = OT_ERROR_ALREADY);
}
}
aReceiver.SetNext(mReceivers);
mReceivers = &aReceiver;
exit:
return error;
} }
otError Udp::RemoveReceiver(UdpReceiver &aReceiver) otError Udp::RemoveReceiver(UdpReceiver &aReceiver)
{ {
otError error = OT_ERROR_NOT_FOUND; otError error;
if (mReceivers == &aReceiver) SuccessOrExit(error = mReceivers.Remove(aReceiver));
{ aReceiver.SetNext(NULL);
mReceivers = mReceivers->GetNext();
aReceiver.SetNext(NULL);
error = OT_ERROR_NONE;
}
else
{
for (UdpReceiver *handler = mReceivers; handler; handler = handler->GetNext())
{
if (handler->GetNext() == &aReceiver)
{
handler->SetNext(aReceiver.GetNext());
aReceiver.SetNext(NULL);
error = OT_ERROR_NONE;
break;
}
}
}
exit:
return error; return error;
} }
void Udp::AddSocket(UdpSocket &aSocket) void Udp::AddSocket(UdpSocket &aSocket)
{ {
for (UdpSocket *cur = mSockets; cur; cur = cur->GetNext()) mSockets.Add(aSocket);
{
if (cur == &aSocket)
{
ExitNow();
}
}
aSocket.SetNext(mSockets);
mSockets = &aSocket;
exit:
return;
} }
void Udp::RemoveSocket(UdpSocket &aSocket) void Udp::RemoveSocket(UdpSocket &aSocket)
{ {
if (mSockets == &aSocket) SuccessOrExit(mSockets.Remove(aSocket));
{
mSockets = mSockets->GetNext();
}
else
{
for (UdpSocket *socket = mSockets; socket; socket = socket->GetNext())
{
if (socket->GetNext() == &aSocket)
{
socket->SetNext(aSocket.GetNext());
break;
}
}
}
aSocket.SetNext(NULL); aSocket.SetNext(NULL);
exit:
return;
} }
uint16_t Udp::GetEphemeralPort(void) uint16_t Udp::GetEphemeralPort(void)
@@ -382,7 +328,7 @@ otError Udp::HandleMessage(Message &aMessage, MessageInfo &aMessageInfo)
VerifyOrExit(IsMle(GetInstance(), aMessageInfo.mSockPort)); VerifyOrExit(IsMle(GetInstance(), aMessageInfo.mSockPort));
#endif #endif
for (UdpReceiver *receiver = mReceivers; receiver; receiver = receiver->GetNext()) for (UdpReceiver *receiver = mReceivers.GetHead(); receiver; receiver = receiver->GetNext())
{ {
VerifyOrExit(!receiver->HandleMessage(aMessage, aMessageInfo)); VerifyOrExit(!receiver->HandleMessage(aMessage, aMessageInfo));
} }
@@ -396,7 +342,7 @@ exit:
void Udp::HandlePayload(Message &aMessage, MessageInfo &aMessageInfo) void Udp::HandlePayload(Message &aMessage, MessageInfo &aMessageInfo)
{ {
// find socket // find socket
for (UdpSocket *socket = mSockets; socket; socket = socket->GetNext()) for (UdpSocket *socket = mSockets.GetHead(); socket; socket = socket->GetNext())
{ {
if (socket->GetSockName().mPort != aMessageInfo.GetSockPort()) if (socket->GetSockName().mPort != aMessageInfo.GetSockPort())
{ {
+7 -12
View File
@@ -38,6 +38,7 @@
#include <openthread/udp.h> #include <openthread/udp.h>
#include "common/linked_list.hpp"
#include "common/locator.hpp" #include "common/locator.hpp"
#include "net/ip6_headers.hpp" #include "net/ip6_headers.hpp"
@@ -60,7 +61,7 @@ class Udp;
* This class implements a UDP receiver. * This class implements a UDP receiver.
* *
*/ */
class UdpReceiver : public otUdpReceiver class UdpReceiver : public otUdpReceiver, public LinkedListEntry<UdpReceiver>
{ {
friend class Udp; friend class Udp;
@@ -80,9 +81,6 @@ public:
} }
private: private:
UdpReceiver *GetNext(void) { return static_cast<UdpReceiver *>(mNext); }
void SetNext(UdpReceiver *aReceiver) { mNext = static_cast<otUdpReceiver *>(aReceiver); }
bool HandleMessage(Message &aMessage, const MessageInfo &aMessageInfo) bool HandleMessage(Message &aMessage, const MessageInfo &aMessageInfo)
{ {
return mHandler(mContext, &aMessage, &aMessageInfo); return mHandler(mContext, &aMessage, &aMessageInfo);
@@ -93,7 +91,7 @@ private:
* This class implements a UDP/IPv6 socket. * This class implements a UDP/IPv6 socket.
* *
*/ */
class UdpSocket : public otUdpSocket, public InstanceLocator class UdpSocket : public otUdpSocket, public InstanceLocator, public LinkedListEntry<UdpSocket>
{ {
friend class Udp; friend class Udp;
@@ -202,9 +200,6 @@ public:
SockAddr &GetPeerName(void) { return *static_cast<SockAddr *>(&mPeerName); } SockAddr &GetPeerName(void) { return *static_cast<SockAddr *>(&mPeerName); }
private: private:
UdpSocket *GetNext(void) { return static_cast<UdpSocket *>(mNext); }
void SetNext(UdpSocket *socket) { mNext = static_cast<otUdpSocket *>(socket); }
void HandleUdpReceive(Message &aMessage, const MessageInfo &aMessageInfo) void HandleUdpReceive(Message &aMessage, const MessageInfo &aMessageInfo)
{ {
mHandler(mContext, &aMessage, &aMessageInfo); mHandler(mContext, &aMessage, &aMessageInfo);
@@ -329,7 +324,7 @@ public:
void UpdateChecksum(Message &aMessage, uint16_t aChecksum); void UpdateChecksum(Message &aMessage, uint16_t aChecksum);
#if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
otUdpSocket *GetUdpSockets(void) { return mSockets; } otUdpSocket *GetUdpSockets(void) { return mSockets.GetHead(); }
#endif #endif
#if OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE #if OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE
@@ -354,9 +349,9 @@ private:
kDynamicPortMax = 65535, ///< Service Name and Transport Protocol Port Number Registry kDynamicPortMax = 65535, ///< Service Name and Transport Protocol Port Number Registry
}; };
uint16_t mEphemeralPort; uint16_t mEphemeralPort;
UdpReceiver *mReceivers; LinkedList<UdpReceiver> mReceivers;
UdpSocket * mSockets; LinkedList<UdpSocket> mSockets;
#if OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE #if OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE
void * mUdpForwarderContext; void * mUdpForwarderContext;
otUdpForwarder mUdpForwarder; otUdpForwarder mUdpForwarder;
+5
View File
@@ -111,6 +111,7 @@ check_PROGRAMS += \
test-hmac-sha256 \ test-hmac-sha256 \
test-ip6-address \ test-ip6-address \
test-link-quality \ test-link-quality \
test-linked-list \
test-lowpan \ test-lowpan \
test-mac-frame \ test-mac-frame \
test-message \ test-message \
@@ -185,6 +186,9 @@ test_ip6_address_SOURCES = test_platform.cpp test_ip6_address.cpp
test_link_quality_LDADD = $(COMMON_LDADD) test_link_quality_LDADD = $(COMMON_LDADD)
test_link_quality_SOURCES = test_platform.cpp test_link_quality.cpp test_link_quality_SOURCES = test_platform.cpp test_link_quality.cpp
test_linked_list_LDADD = $(COMMON_LDADD)
test_linked_list_SOURCES = test_platform.cpp test_linked_list.cpp
test_lowpan_LDADD = $(COMMON_LDADD) test_lowpan_LDADD = $(COMMON_LDADD)
test_lowpan_SOURCES = test_platform.cpp test_lowpan.cpp test_util.cpp test_lowpan_SOURCES = test_platform.cpp test_lowpan.cpp test_util.cpp
@@ -243,6 +247,7 @@ PRETTY_FILES = \
$(test_heap_SOURCES) \ $(test_heap_SOURCES) \
$(test_hmac_sha256_SOURCES) \ $(test_hmac_sha256_SOURCES) \
$(test_link_quality_SOURCES) \ $(test_link_quality_SOURCES) \
$(test_linked_list_SOURCES) \
$(test_lowpan_SOURCES) \ $(test_lowpan_SOURCES) \
$(test_mac_frame_SOURCES) \ $(test_mac_frame_SOURCES) \
$(test_message_queue_SOURCES) \ $(test_message_queue_SOURCES) \
+152
View File
@@ -0,0 +1,152 @@
/*
* Copyright (c) 2019, 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.
*/
#include <stdarg.h>
#include "test_platform.h"
#include <openthread/config.h>
#include "common/debug.hpp"
#include "common/instance.hpp"
#include "common/linked_list.hpp"
#include "test_util.h"
struct EntryBase
{
EntryBase *mNext;
};
struct Entry : public EntryBase, ot::LinkedListEntry<Entry>
{
};
// This function verifies the content of the linked list matches a given list of entries.
void VerifyLinkedListContent(const ot::LinkedList<Entry> &aList, ...)
{
va_list args;
Entry * argEntry;
va_start(args, aList);
for (const Entry *entry = aList.GetHead(); entry; entry = entry->GetNext())
{
argEntry = va_arg(args, Entry *);
VerifyOrQuit(argEntry != NULL, "List contains more entries than expected");
VerifyOrQuit(argEntry == entry, "List does not contain the same entry");
VerifyOrQuit(aList.Contains(*argEntry), "List::Contains() failed");
}
argEntry = va_arg(args, Entry *);
VerifyOrQuit(argEntry == NULL, "List contains less entries than expected");
}
void TestLinkedList(void)
{
Entry a, b, c, d, e;
ot::LinkedList<Entry> list;
VerifyOrQuit(list.IsEmpty(), "LinkedList::IsEmpty() failed after init");
VerifyOrQuit(list.GetHead() == NULL, "LinkedList::GetHead() failed after init");
VerifyOrQuit(list.Pop() == NULL, "LinkedList::Pop() failed when empty");
VerifyLinkedListContent(list, NULL);
list.Push(a);
VerifyOrQuit(!list.IsEmpty(), "LinkedList::IsEmpty() failed");
VerifyLinkedListContent(list, &a, NULL);
SuccessOrQuit(list.Add(b), "LinkedList::Add() failed");
VerifyLinkedListContent(list, &b, &a, NULL);
list.Push(c);
VerifyLinkedListContent(list, &c, &b, &a, NULL);
SuccessOrQuit(list.Add(d), "LinkedList::Add() failed");
VerifyLinkedListContent(list, &d, &c, &b, &a, NULL);
SuccessOrQuit(list.Add(e), "LinkedList::Add() failed");
VerifyLinkedListContent(list, &e, &d, &c, &b, &a, NULL);
VerifyOrQuit(list.Add(a) == OT_ERROR_ALREADY, "LinkedList::Add() did not detect duplicate");
VerifyOrQuit(list.Add(b) == OT_ERROR_ALREADY, "LinkedList::Add() did not detect duplicate");
VerifyOrQuit(list.Add(d) == OT_ERROR_ALREADY, "LinkedList::Add() did not detect duplicate");
VerifyOrQuit(list.Add(e) == OT_ERROR_ALREADY, "LinkedList::Add() did not detect duplicate");
VerifyOrQuit(list.Pop() == &e, "LinkedList::Pop() failed");
VerifyLinkedListContent(list, &d, &c, &b, &a, NULL);
list.SetHead(&e);
VerifyLinkedListContent(list, &e, &d, &c, &b, &a, NULL);
SuccessOrQuit(list.Remove(c), "LinkedList::Remove() failed");
VerifyLinkedListContent(list, &e, &d, &b, &a, NULL);
VerifyOrQuit(list.Remove(c) == OT_ERROR_NOT_FOUND, "LinkedList::Remove() failed");
VerifyLinkedListContent(list, &e, &d, &b, &a, NULL);
SuccessOrQuit(list.Remove(e), "LinkedList::Remove() failed");
VerifyLinkedListContent(list, &d, &b, &a, NULL);
SuccessOrQuit(list.Remove(a), "LinkedList::Remove() failed");
VerifyLinkedListContent(list, &d, &b, NULL);
list.Push(a);
list.Push(c);
list.Push(e);
VerifyLinkedListContent(list, &e, &c, &a, &d, &b, NULL);
VerifyOrQuit(list.PopAfter(a) == &d, "LinkedList::PopAfter() failed");
VerifyLinkedListContent(list, &e, &c, &a, &b, NULL);
VerifyOrQuit(list.PopAfter(b) == NULL, "LinkedList::PopAfter() failed");
VerifyLinkedListContent(list, &e, &c, &a, &b, NULL);
VerifyOrQuit(list.PopAfter(e) == &c, "LinkedList::PopAfter() failed");
VerifyLinkedListContent(list, &e, &a, &b, NULL);
list.PushAfter(c, b);
VerifyLinkedListContent(list, &e, &a, &b, &c, NULL);
list.PushAfter(d, a);
VerifyLinkedListContent(list, &e, &a, &d, &b, &c, NULL);
list.Clear();
VerifyOrQuit(list.IsEmpty(), "LinkedList::IsEmpty() failed after Clear()");
VerifyLinkedListContent(list, NULL);
}
#ifdef ENABLE_TEST_MAIN
int main(void)
{
TestLinkedList();
printf("All tests passed\n");
return 0;
}
#endif