mirror of
https://github.com/espressif/openthread.git
synced 2026-08-20 09:29:51 +00:00
[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:
committed by
Jonathan Hui
parent
15e26f0e64
commit
e17c82b0b9
@@ -310,6 +310,7 @@ HEADERS_COMMON = \
|
||||
common/encoding.hpp \
|
||||
common/extension.hpp \
|
||||
common/instance.hpp \
|
||||
common/linked_list.hpp \
|
||||
common/locator.hpp \
|
||||
common/locator-getters.hpp \
|
||||
common/logging.hpp \
|
||||
|
||||
+5
-32
@@ -49,7 +49,7 @@ namespace Coap {
|
||||
CoapBase::CoapBase(Instance &aInstance, Sender aSender)
|
||||
: InstanceLocator(aInstance)
|
||||
, mRetransmissionTimer(aInstance, &Coap::HandleRetransmissionTimer, this)
|
||||
, mResources(NULL)
|
||||
, mResources()
|
||||
, mContext(NULL)
|
||||
, mInterceptor(NULL)
|
||||
, mResponsesQueue(aInstance)
|
||||
@@ -81,40 +81,13 @@ void CoapBase::ClearRequestsAndResponses(void)
|
||||
|
||||
otError CoapBase::AddResource(Resource &aResource)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
for (Resource *cur = mResources; cur; cur = cur->GetNext())
|
||||
{
|
||||
VerifyOrExit(cur != &aResource, error = OT_ERROR_ALREADY);
|
||||
}
|
||||
|
||||
aResource.mNext = mResources;
|
||||
mResources = &aResource;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
return mResources.Add(aResource);
|
||||
}
|
||||
|
||||
void CoapBase::RemoveResource(Resource &aResource)
|
||||
{
|
||||
if (mResources == &aResource)
|
||||
{
|
||||
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;
|
||||
mResources.Remove(aResource);
|
||||
aResource.SetNext(NULL);
|
||||
}
|
||||
|
||||
void CoapBase::SetDefaultHandler(otCoapRequestHandler aHandler, void *aContext)
|
||||
@@ -611,7 +584,7 @@ void CoapBase::ProcessReceivedRequest(Message &aMessage, const Ip6::MessageInfo
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
+3
-10
@@ -35,6 +35,7 @@
|
||||
|
||||
#include "coap/coap_message.hpp"
|
||||
#include "common/debug.hpp"
|
||||
#include "common/linked_list.hpp"
|
||||
#include "common/locator.hpp"
|
||||
#include "common/message.hpp"
|
||||
#include "common/timer.hpp"
|
||||
@@ -175,7 +176,7 @@ private:
|
||||
* This class implements CoAP resource handling.
|
||||
*
|
||||
*/
|
||||
class Resource : public otCoapResource
|
||||
class Resource : public otCoapResource, public LinkedListEntry<Resource>
|
||||
{
|
||||
friend class CoapBase;
|
||||
|
||||
@@ -200,14 +201,6 @@ public:
|
||||
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.
|
||||
*
|
||||
@@ -678,7 +671,7 @@ private:
|
||||
uint16_t mMessageId;
|
||||
TimerMilliContext mRetransmissionTimer;
|
||||
|
||||
Resource *mResources;
|
||||
LinkedList<Resource> mResources;
|
||||
|
||||
void * mContext;
|
||||
Interceptor mInterceptor;
|
||||
|
||||
@@ -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_
|
||||
@@ -54,7 +54,7 @@ Notifier::Notifier(Instance &aInstance)
|
||||
, mFlagsToSignal(0)
|
||||
, mSignaledFlags(0)
|
||||
, mTask(aInstance, &Notifier::HandleStateChanged, this)
|
||||
, mCallbacks(NULL)
|
||||
, mCallbacks()
|
||||
{
|
||||
for (unsigned int i = 0; i < kMaxExternalHandlers; i++)
|
||||
{
|
||||
@@ -65,8 +65,7 @@ Notifier::Notifier(Instance &aInstance)
|
||||
|
||||
void Notifier::RegisterCallback(Callback &aCallback)
|
||||
{
|
||||
aCallback.mNext = mCallbacks;
|
||||
mCallbacks = &aCallback;
|
||||
mCallbacks.Push(aCallback);
|
||||
}
|
||||
|
||||
otError Notifier::RegisterCallback(otStateChangedCallback aCallback, void *aContext)
|
||||
@@ -151,7 +150,7 @@ void Notifier::HandleStateChanged(void)
|
||||
|
||||
LogChangedFlags(flags);
|
||||
|
||||
for (Callback *callback = mCallbacks; callback != NULL; callback = callback->mNext)
|
||||
for (Callback *callback = mCallbacks.GetHead(); callback != NULL; callback = callback->GetNext())
|
||||
{
|
||||
callback->Invoke(flags);
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include <openthread/instance.h>
|
||||
#include <openthread/platform/toolchain.h>
|
||||
|
||||
#include "common/linked_list.hpp"
|
||||
#include "common/locator.hpp"
|
||||
#include "common/tasklet.hpp"
|
||||
|
||||
@@ -79,9 +80,10 @@ public:
|
||||
* This class defines a `Notifier` callback instance.
|
||||
*
|
||||
*/
|
||||
class Callback : public OwnerLocator
|
||||
class Callback : public OwnerLocator, public LinkedListEntry<Callback>
|
||||
{
|
||||
friend class Notifier;
|
||||
friend class LinkedListEntry<Callback>;
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -232,11 +234,11 @@ private:
|
||||
void LogChangedFlags(otChangedFlags aFlags) const;
|
||||
const char *FlagToString(otChangedFlags aFlag) const;
|
||||
|
||||
otChangedFlags mFlagsToSignal;
|
||||
otChangedFlags mSignaledFlags;
|
||||
Tasklet mTask;
|
||||
Callback * mCallbacks;
|
||||
ExternalCallback mExternalCallbacks[kMaxExternalHandlers];
|
||||
otChangedFlags mFlagsToSignal;
|
||||
otChangedFlags mSignaledFlags;
|
||||
Tasklet mTask;
|
||||
LinkedList<Callback> mCallbacks;
|
||||
ExternalCallback mExternalCallbacks[kMaxExternalHandlers];
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+23
-50
@@ -100,73 +100,45 @@ void TimerMilli::Stop(void)
|
||||
|
||||
void TimerScheduler::Add(Timer &aTimer, const AlarmApi &aAlarmApi)
|
||||
{
|
||||
Timer *prev = NULL;
|
||||
Time now(aAlarmApi.AlarmGetNow());
|
||||
|
||||
Remove(aTimer, aAlarmApi);
|
||||
|
||||
if (mHead == NULL)
|
||||
for (Timer *cur = mTimerList.GetHead(); cur; prev = cur, cur = cur->GetNext())
|
||||
{
|
||||
mHead = &aTimer;
|
||||
aTimer.mNext = NULL;
|
||||
if (aTimer.DoesFireBefore(*cur, now))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (prev == NULL)
|
||||
{
|
||||
mTimerList.Push(aTimer);
|
||||
SetAlarm(aAlarmApi);
|
||||
}
|
||||
else
|
||||
{
|
||||
Timer *prev = NULL;
|
||||
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;
|
||||
}
|
||||
mTimerList.PushAfter(aTimer, *prev);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (Timer *cur = mHead; cur; cur = cur->mNext)
|
||||
{
|
||||
if (cur->mNext == &aTimer)
|
||||
{
|
||||
cur->mNext = aTimer.mNext;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mTimerList.Remove(aTimer);
|
||||
}
|
||||
|
||||
aTimer.mNext = &aTimer;
|
||||
aTimer.SetNext(&aTimer);
|
||||
|
||||
exit:
|
||||
return;
|
||||
@@ -174,16 +146,17 @@ exit:
|
||||
|
||||
void TimerScheduler::SetAlarm(const AlarmApi &aAlarmApi)
|
||||
{
|
||||
if (mHead == NULL)
|
||||
if (mTimerList.IsEmpty())
|
||||
{
|
||||
aAlarmApi.AlarmStop(&GetInstance());
|
||||
}
|
||||
else
|
||||
{
|
||||
Timer * timer = mTimerList.GetHead();
|
||||
Time now(aAlarmApi.AlarmGetNow());
|
||||
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);
|
||||
}
|
||||
@@ -191,7 +164,7 @@ void TimerScheduler::SetAlarm(const AlarmApi &aAlarmApi)
|
||||
|
||||
void TimerScheduler::ProcessTimers(const AlarmApi &aAlarmApi)
|
||||
{
|
||||
Timer *timer = mHead;
|
||||
Timer *timer = mTimerList.GetHead();
|
||||
|
||||
if (timer)
|
||||
{
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include <openthread/platform/alarm-milli.h>
|
||||
|
||||
#include "common/debug.hpp"
|
||||
#include "common/linked_list.hpp"
|
||||
#include "common/locator.hpp"
|
||||
#include "common/tasklet.hpp"
|
||||
#include "common/time.hpp"
|
||||
@@ -65,9 +66,10 @@ class TimerMilliScheduler;
|
||||
* 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 LinkedListEntry<Timer>;
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -273,7 +275,7 @@ protected:
|
||||
*/
|
||||
explicit TimerScheduler(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mHead(NULL)
|
||||
, mTimerList()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -311,7 +313,7 @@ protected:
|
||||
*/
|
||||
void SetAlarm(const AlarmApi &aAlarmApi);
|
||||
|
||||
Timer *mHead;
|
||||
LinkedList<Timer> mTimerList;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+3
-17
@@ -50,7 +50,7 @@ namespace Ip6 {
|
||||
|
||||
Icmp::Icmp(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mHandlers(NULL)
|
||||
, mHandlers()
|
||||
, mEchoSequence(1)
|
||||
, mEchoMode(OT_ICMP6_ECHO_HANDLER_ALL)
|
||||
{
|
||||
@@ -63,21 +63,7 @@ Message *Icmp::NewMessage(uint16_t aReserved)
|
||||
|
||||
otError Icmp::RegisterHandler(IcmpHandler &aHandler)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
for (IcmpHandler *cur = mHandlers; cur; cur = cur->GetNext())
|
||||
{
|
||||
if (cur == &aHandler)
|
||||
{
|
||||
ExitNow(error = OT_ERROR_ALREADY);
|
||||
}
|
||||
}
|
||||
|
||||
aHandler.mNext = mHandlers;
|
||||
mHandlers = &aHandler;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
return mHandlers.Add(aHandler);
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
for (IcmpHandler *handler = mHandlers; handler; handler = handler->GetNext())
|
||||
for (IcmpHandler *handler = mHandlers.GetHead(); handler; handler = handler->GetNext())
|
||||
{
|
||||
handler->HandleReceiveMessage(aMessage, aMessageInfo, icmp6Header);
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <openthread/icmp6.h>
|
||||
|
||||
#include "common/encoding.hpp"
|
||||
#include "common/linked_list.hpp"
|
||||
#include "common/locator.hpp"
|
||||
#include "net/ip6_headers.hpp"
|
||||
|
||||
@@ -201,7 +202,7 @@ public:
|
||||
* This class implements ICMPv6 message handlers.
|
||||
*
|
||||
*/
|
||||
class IcmpHandler : public otIcmp6Handler
|
||||
class IcmpHandler : public otIcmp6Handler, public LinkedListEntry<IcmpHandler>
|
||||
{
|
||||
friend class Icmp;
|
||||
|
||||
@@ -225,8 +226,6 @@ private:
|
||||
{
|
||||
mReceiveCallback(mContext, &aMessage, &aMessageInfo, &aIcmp6Header);
|
||||
}
|
||||
|
||||
IcmpHandler *GetNext(void) { return static_cast<IcmpHandler *>(mNext); }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -347,7 +346,7 @@ public:
|
||||
private:
|
||||
otError HandleEchoRequest(Message &aRequestMessage, const MessageInfo &aMessageInfo);
|
||||
|
||||
IcmpHandler *mHandlers;
|
||||
LinkedList<IcmpHandler> mHandlers;
|
||||
|
||||
uint16_t mEchoSequence;
|
||||
otIcmp6EchoMode mEchoMode;
|
||||
|
||||
+45
-107
@@ -82,8 +82,8 @@ const otNetifMulticastAddress Netif::kLinkLocalAllRoutersMulticastAddress = {
|
||||
|
||||
Netif::Netif(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mUnicastAddresses(NULL)
|
||||
, mMulticastAddresses(NULL)
|
||||
, mUnicastAddresses()
|
||||
, mMulticastAddresses()
|
||||
, mMulticastPromiscuous(false)
|
||||
, mNext(NULL)
|
||||
, mAddressCallback(NULL)
|
||||
@@ -107,7 +107,7 @@ bool Netif::IsMulticastSubscribed(const Address &aAddress) const
|
||||
{
|
||||
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)
|
||||
{
|
||||
@@ -121,10 +121,10 @@ exit:
|
||||
|
||||
void Netif::SubscribeAllNodesMulticast(void)
|
||||
{
|
||||
assert(mMulticastAddresses == NULL);
|
||||
assert(mMulticastAddresses.IsEmpty());
|
||||
|
||||
mMulticastAddresses = static_cast<NetifMulticastAddress *>(
|
||||
const_cast<otNetifMulticastAddress *>(&kLinkLocalAllNodesMulticastAddress));
|
||||
mMulticastAddresses.SetHead(static_cast<NetifMulticastAddress *>(
|
||||
const_cast<otNetifMulticastAddress *>(&kLinkLocalAllNodesMulticastAddress)));
|
||||
|
||||
if (mAddressCallback != NULL)
|
||||
{
|
||||
@@ -140,9 +140,9 @@ void Netif::SubscribeAllNodesMulticast(void)
|
||||
|
||||
void Netif::UnsubscribeAllNodesMulticast(void)
|
||||
{
|
||||
assert(mMulticastAddresses == NULL || mMulticastAddresses == &kLinkLocalAllNodesMulticastAddress);
|
||||
assert(mMulticastAddresses.IsEmpty() || mMulticastAddresses.GetHead() == &kLinkLocalAllNodesMulticastAddress);
|
||||
|
||||
mMulticastAddresses = NULL;
|
||||
mMulticastAddresses.SetHead(NULL);
|
||||
|
||||
if (mAddressCallback != NULL)
|
||||
{
|
||||
@@ -160,14 +160,14 @@ otError Netif::SubscribeAllRoutersMulticast(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
if (mMulticastAddresses == &kLinkLocalAllNodesMulticastAddress)
|
||||
if (mMulticastAddresses.GetHead() == &kLinkLocalAllNodesMulticastAddress)
|
||||
{
|
||||
mMulticastAddresses = static_cast<NetifMulticastAddress *>(
|
||||
const_cast<otNetifMulticastAddress *>(&kLinkLocalAllRoutersMulticastAddress));
|
||||
mMulticastAddresses.SetHead(static_cast<NetifMulticastAddress *>(
|
||||
const_cast<otNetifMulticastAddress *>(&kLinkLocalAllRoutersMulticastAddress)));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (NetifMulticastAddress *cur = mMulticastAddresses; cur; cur = cur->GetNext())
|
||||
for (NetifMulticastAddress *cur = mMulticastAddresses.GetHead(); cur; cur = cur->GetNext())
|
||||
{
|
||||
if (cur == &kLinkLocalAllRoutersMulticastAddress)
|
||||
{
|
||||
@@ -201,14 +201,14 @@ otError Netif::UnsubscribeAllRoutersMulticast(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
if (mMulticastAddresses == &kLinkLocalAllRoutersMulticastAddress)
|
||||
if (mMulticastAddresses.GetHead() == &kLinkLocalAllRoutersMulticastAddress)
|
||||
{
|
||||
mMulticastAddresses = static_cast<NetifMulticastAddress *>(
|
||||
const_cast<otNetifMulticastAddress *>(&kLinkLocalAllNodesMulticastAddress));
|
||||
mMulticastAddresses.SetHead(static_cast<NetifMulticastAddress *>(
|
||||
const_cast<otNetifMulticastAddress *>(&kLinkLocalAllNodesMulticastAddress)));
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
for (NetifMulticastAddress *cur = mMulticastAddresses; cur; cur = cur->GetNext())
|
||||
for (NetifMulticastAddress *cur = mMulticastAddresses.GetHead(); cur; cur = cur->GetNext())
|
||||
{
|
||||
if (cur->mNext == &kLinkLocalAllRoutersMulticastAddress)
|
||||
{
|
||||
@@ -240,18 +240,9 @@ exit:
|
||||
|
||||
otError Netif::SubscribeMulticast(NetifMulticastAddress &aAddress)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
otError error;
|
||||
|
||||
for (NetifMulticastAddress *cur = mMulticastAddresses; cur; cur = cur->GetNext())
|
||||
{
|
||||
if (cur == &aAddress)
|
||||
{
|
||||
ExitNow(error = OT_ERROR_ALREADY);
|
||||
}
|
||||
}
|
||||
|
||||
aAddress.mNext = mMulticastAddresses;
|
||||
mMulticastAddresses = &aAddress;
|
||||
SuccessOrExit(error = mMulticastAddresses.Add(aAddress));
|
||||
|
||||
if (mAddressCallback != NULL)
|
||||
{
|
||||
@@ -266,39 +257,18 @@ exit:
|
||||
|
||||
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();
|
||||
ExitNow();
|
||||
}
|
||||
else if (mMulticastAddresses != NULL)
|
||||
{
|
||||
for (NetifMulticastAddress *cur = mMulticastAddresses; cur->GetNext(); cur = cur->GetNext())
|
||||
{
|
||||
if (cur->mNext == &aAddress)
|
||||
{
|
||||
cur->mNext = aAddress.mNext;
|
||||
ExitNow();
|
||||
}
|
||||
}
|
||||
mAddressCallback(&aAddress.mAddress, kMulticastPrefixLength, false, mAddressCallbackContext);
|
||||
}
|
||||
|
||||
ExitNow(error = OT_ERROR_NOT_FOUND);
|
||||
Get<Notifier>().Signal(OT_CHANGED_IP6_MULTICAST_UNSUBSCRIBED);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -332,7 +302,7 @@ otError Netif::SubscribeExternalMulticast(const Address &aAddress)
|
||||
otError error = OT_ERROR_NONE;
|
||||
NetifMulticastAddress *entry;
|
||||
|
||||
VerifyOrExit(mMulticastAddresses != NULL, error = OT_ERROR_INVALID_STATE);
|
||||
VerifyOrExit(!mMulticastAddresses.IsEmpty(), error = OT_ERROR_INVALID_STATE);
|
||||
|
||||
if (IsMulticastSubscribed(aAddress))
|
||||
{
|
||||
@@ -352,9 +322,8 @@ otError Netif::SubscribeExternalMulticast(const Address &aAddress)
|
||||
VerifyOrExit(entry < OT_ARRAY_END(mExtMulticastAddresses), error = OT_ERROR_NO_BUFS);
|
||||
|
||||
// Copy the address into the available entry and add it to linked-list.
|
||||
entry->mAddress = aAddress;
|
||||
entry->mNext = mMulticastAddresses;
|
||||
mMulticastAddresses = entry;
|
||||
entry->mAddress = aAddress;
|
||||
mMulticastAddresses.Push(*entry);
|
||||
Get<Notifier>().Signal(OT_CHANGED_IP6_MULTICAST_SUBSCRIBED);
|
||||
|
||||
exit:
|
||||
@@ -367,7 +336,7 @@ otError Netif::UnsubscribeExternalMulticast(const Address &aAddress)
|
||||
NetifMulticastAddress *entry;
|
||||
NetifMulticastAddress *last = NULL;
|
||||
|
||||
for (entry = mMulticastAddresses; entry; entry = entry->GetNext())
|
||||
for (entry = mMulticastAddresses.GetHead(); entry; entry = entry->GetNext())
|
||||
{
|
||||
if (entry->GetAddress() == aAddress)
|
||||
{
|
||||
@@ -376,11 +345,11 @@ otError Netif::UnsubscribeExternalMulticast(const Address &aAddress)
|
||||
|
||||
if (last)
|
||||
{
|
||||
last->mNext = entry->GetNext();
|
||||
mMulticastAddresses.PopAfter(*last);
|
||||
}
|
||||
else
|
||||
{
|
||||
mMulticastAddresses = entry->GetNext();
|
||||
mMulticastAddresses.Pop();
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -421,18 +390,9 @@ void Netif::SetAddressCallback(otIp6AddressCallback aCallback, void *aCallbackCo
|
||||
|
||||
otError Netif::AddUnicastAddress(NetifUnicastAddress &aAddress)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
otError error;
|
||||
|
||||
for (NetifUnicastAddress *cur = mUnicastAddresses; cur; cur = cur->GetNext())
|
||||
{
|
||||
if (cur == &aAddress)
|
||||
{
|
||||
ExitNow(error = OT_ERROR_ALREADY);
|
||||
}
|
||||
}
|
||||
|
||||
aAddress.mNext = mUnicastAddresses;
|
||||
mUnicastAddresses = &aAddress;
|
||||
SuccessOrExit(error = mUnicastAddresses.Add(aAddress));
|
||||
|
||||
if (mAddressCallback != NULL)
|
||||
{
|
||||
@@ -447,39 +407,18 @@ exit:
|
||||
|
||||
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();
|
||||
ExitNow();
|
||||
}
|
||||
else if (mUnicastAddresses != NULL)
|
||||
{
|
||||
for (NetifUnicastAddress *cur = mUnicastAddresses; cur->GetNext(); cur = cur->GetNext())
|
||||
{
|
||||
if (cur->mNext == &aAddress)
|
||||
{
|
||||
cur->mNext = aAddress.mNext;
|
||||
ExitNow();
|
||||
}
|
||||
}
|
||||
mAddressCallback(&aAddress.mAddress, aAddress.mPrefixLength, false, mAddressCallbackContext);
|
||||
}
|
||||
|
||||
ExitNow(error = OT_ERROR_NOT_FOUND);
|
||||
Get<Notifier>().Signal(aAddress.mRloc ? OT_CHANGED_THREAD_RLOC_REMOVED : OT_CHANGED_IP6_ADDRESS_REMOVED);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -490,7 +429,7 @@ otError Netif::AddExternalUnicastAddress(const NetifUnicastAddress &aAddress)
|
||||
|
||||
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())
|
||||
{
|
||||
@@ -517,9 +456,8 @@ otError Netif::AddExternalUnicastAddress(const NetifUnicastAddress &aAddress)
|
||||
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.
|
||||
*entry = aAddress;
|
||||
entry->mNext = mUnicastAddresses;
|
||||
mUnicastAddresses = entry;
|
||||
*entry = aAddress;
|
||||
mUnicastAddresses.Push(*entry);
|
||||
|
||||
Get<Notifier>().Signal(OT_CHANGED_IP6_ADDRESS_ADDED);
|
||||
|
||||
@@ -533,7 +471,7 @@ otError Netif::RemoveExternalUnicastAddress(const Address &aAddress)
|
||||
NetifUnicastAddress *entry;
|
||||
NetifUnicastAddress *last = NULL;
|
||||
|
||||
for (entry = mUnicastAddresses; entry; entry = entry->GetNext())
|
||||
for (entry = mUnicastAddresses.GetHead(); entry; entry = entry->GetNext())
|
||||
{
|
||||
if (entry->GetAddress() == aAddress)
|
||||
{
|
||||
@@ -542,11 +480,11 @@ otError Netif::RemoveExternalUnicastAddress(const Address &aAddress)
|
||||
|
||||
if (last)
|
||||
{
|
||||
last->mNext = entry->mNext;
|
||||
mUnicastAddresses.PopAfter(*last);
|
||||
}
|
||||
else
|
||||
{
|
||||
mUnicastAddresses = entry->GetNext();
|
||||
mUnicastAddresses.Pop();
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -582,7 +520,7 @@ bool Netif::IsUnicastAddress(const Address &aAddress) const
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
||||
+10
-32
@@ -36,6 +36,7 @@
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#include "common/linked_list.hpp"
|
||||
#include "common/locator.hpp"
|
||||
#include "common/message.hpp"
|
||||
#include "common/tasklet.hpp"
|
||||
@@ -62,7 +63,7 @@ class Ip6;
|
||||
* This class implements an IPv6 network interface unicast address.
|
||||
*
|
||||
*/
|
||||
class NetifUnicastAddress : public otNetifAddress
|
||||
class NetifUnicastAddress : public otNetifAddress, public LinkedListEntry<NetifUnicastAddress>
|
||||
{
|
||||
friend class Netif;
|
||||
|
||||
@@ -93,29 +94,13 @@ public:
|
||||
{
|
||||
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.
|
||||
*
|
||||
*/
|
||||
class NetifMulticastAddress : public otNetifMulticastAddress
|
||||
class NetifMulticastAddress : public otNetifMulticastAddress, public LinkedListEntry<NetifMulticastAddress>
|
||||
{
|
||||
friend class Netif;
|
||||
|
||||
@@ -160,7 +145,7 @@ public:
|
||||
* This class implements an IPv6 network interface.
|
||||
*
|
||||
*/
|
||||
class Netif : public InstanceLocator
|
||||
class Netif : public InstanceLocator, public LinkedListEntry<Netif>
|
||||
{
|
||||
friend class Ip6;
|
||||
|
||||
@@ -173,13 +158,6 @@ public:
|
||||
*/
|
||||
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.
|
||||
*
|
||||
@@ -195,7 +173,7 @@ public:
|
||||
* @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.
|
||||
@@ -295,7 +273,7 @@ public:
|
||||
* @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.
|
||||
@@ -402,10 +380,10 @@ private:
|
||||
kMulticastPrefixLength = 128, ///< Multicast prefix length used to notify internal address changes.
|
||||
};
|
||||
|
||||
NetifUnicastAddress * mUnicastAddresses;
|
||||
NetifMulticastAddress *mMulticastAddresses;
|
||||
bool mMulticastPromiscuous;
|
||||
Netif * mNext;
|
||||
LinkedList<NetifUnicastAddress> mUnicastAddresses;
|
||||
LinkedList<NetifMulticastAddress> mMulticastAddresses;
|
||||
bool mMulticastPromiscuous;
|
||||
Netif * mNext;
|
||||
|
||||
otIp6AddressCallback mAddressCallback;
|
||||
void * mAddressCallbackContext;
|
||||
|
||||
+14
-68
@@ -205,8 +205,8 @@ exit:
|
||||
Udp::Udp(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mEphemeralPort(kDynamicPortMin)
|
||||
, mReceivers(NULL)
|
||||
, mSockets(NULL)
|
||||
, mReceivers()
|
||||
, mSockets()
|
||||
#if OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE
|
||||
, mUdpForwarderContext(NULL)
|
||||
, mUdpForwarder(NULL)
|
||||
@@ -216,86 +216,32 @@ Udp::Udp(Instance &aInstance)
|
||||
|
||||
otError Udp::AddReceiver(UdpReceiver &aReceiver)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
for (UdpReceiver *cur = mReceivers; cur; cur = cur->GetNext())
|
||||
{
|
||||
if (cur == &aReceiver)
|
||||
{
|
||||
ExitNow(error = OT_ERROR_ALREADY);
|
||||
}
|
||||
}
|
||||
|
||||
aReceiver.SetNext(mReceivers);
|
||||
mReceivers = &aReceiver;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
return mReceivers.Add(aReceiver);
|
||||
}
|
||||
|
||||
otError Udp::RemoveReceiver(UdpReceiver &aReceiver)
|
||||
{
|
||||
otError error = OT_ERROR_NOT_FOUND;
|
||||
otError error;
|
||||
|
||||
if (mReceivers == &aReceiver)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
SuccessOrExit(error = mReceivers.Remove(aReceiver));
|
||||
aReceiver.SetNext(NULL);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Udp::AddSocket(UdpSocket &aSocket)
|
||||
{
|
||||
for (UdpSocket *cur = mSockets; cur; cur = cur->GetNext())
|
||||
{
|
||||
if (cur == &aSocket)
|
||||
{
|
||||
ExitNow();
|
||||
}
|
||||
}
|
||||
|
||||
aSocket.SetNext(mSockets);
|
||||
mSockets = &aSocket;
|
||||
|
||||
exit:
|
||||
return;
|
||||
mSockets.Add(aSocket);
|
||||
}
|
||||
|
||||
void Udp::RemoveSocket(UdpSocket &aSocket)
|
||||
{
|
||||
if (mSockets == &aSocket)
|
||||
{
|
||||
mSockets = mSockets->GetNext();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (UdpSocket *socket = mSockets; socket; socket = socket->GetNext())
|
||||
{
|
||||
if (socket->GetNext() == &aSocket)
|
||||
{
|
||||
socket->SetNext(aSocket.GetNext());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SuccessOrExit(mSockets.Remove(aSocket));
|
||||
aSocket.SetNext(NULL);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t Udp::GetEphemeralPort(void)
|
||||
@@ -382,7 +328,7 @@ otError Udp::HandleMessage(Message &aMessage, MessageInfo &aMessageInfo)
|
||||
VerifyOrExit(IsMle(GetInstance(), aMessageInfo.mSockPort));
|
||||
#endif
|
||||
|
||||
for (UdpReceiver *receiver = mReceivers; receiver; receiver = receiver->GetNext())
|
||||
for (UdpReceiver *receiver = mReceivers.GetHead(); receiver; receiver = receiver->GetNext())
|
||||
{
|
||||
VerifyOrExit(!receiver->HandleMessage(aMessage, aMessageInfo));
|
||||
}
|
||||
@@ -396,7 +342,7 @@ exit:
|
||||
void Udp::HandlePayload(Message &aMessage, MessageInfo &aMessageInfo)
|
||||
{
|
||||
// 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())
|
||||
{
|
||||
|
||||
+7
-12
@@ -38,6 +38,7 @@
|
||||
|
||||
#include <openthread/udp.h>
|
||||
|
||||
#include "common/linked_list.hpp"
|
||||
#include "common/locator.hpp"
|
||||
#include "net/ip6_headers.hpp"
|
||||
|
||||
@@ -60,7 +61,7 @@ class Udp;
|
||||
* This class implements a UDP receiver.
|
||||
*
|
||||
*/
|
||||
class UdpReceiver : public otUdpReceiver
|
||||
class UdpReceiver : public otUdpReceiver, public LinkedListEntry<UdpReceiver>
|
||||
{
|
||||
friend class Udp;
|
||||
|
||||
@@ -80,9 +81,6 @@ public:
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return mHandler(mContext, &aMessage, &aMessageInfo);
|
||||
@@ -93,7 +91,7 @@ private:
|
||||
* 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;
|
||||
|
||||
@@ -202,9 +200,6 @@ public:
|
||||
SockAddr &GetPeerName(void) { return *static_cast<SockAddr *>(&mPeerName); }
|
||||
|
||||
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)
|
||||
{
|
||||
mHandler(mContext, &aMessage, &aMessageInfo);
|
||||
@@ -329,7 +324,7 @@ public:
|
||||
void UpdateChecksum(Message &aMessage, uint16_t aChecksum);
|
||||
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
|
||||
otUdpSocket *GetUdpSockets(void) { return mSockets; }
|
||||
otUdpSocket *GetUdpSockets(void) { return mSockets.GetHead(); }
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE
|
||||
@@ -354,9 +349,9 @@ private:
|
||||
kDynamicPortMax = 65535, ///< Service Name and Transport Protocol Port Number Registry
|
||||
};
|
||||
|
||||
uint16_t mEphemeralPort;
|
||||
UdpReceiver *mReceivers;
|
||||
UdpSocket * mSockets;
|
||||
uint16_t mEphemeralPort;
|
||||
LinkedList<UdpReceiver> mReceivers;
|
||||
LinkedList<UdpSocket> mSockets;
|
||||
#if OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE
|
||||
void * mUdpForwarderContext;
|
||||
otUdpForwarder mUdpForwarder;
|
||||
|
||||
@@ -111,6 +111,7 @@ check_PROGRAMS += \
|
||||
test-hmac-sha256 \
|
||||
test-ip6-address \
|
||||
test-link-quality \
|
||||
test-linked-list \
|
||||
test-lowpan \
|
||||
test-mac-frame \
|
||||
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_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_SOURCES = test_platform.cpp test_lowpan.cpp test_util.cpp
|
||||
|
||||
@@ -243,6 +247,7 @@ PRETTY_FILES = \
|
||||
$(test_heap_SOURCES) \
|
||||
$(test_hmac_sha256_SOURCES) \
|
||||
$(test_link_quality_SOURCES) \
|
||||
$(test_linked_list_SOURCES) \
|
||||
$(test_lowpan_SOURCES) \
|
||||
$(test_mac_frame_SOURCES) \
|
||||
$(test_message_queue_SOURCES) \
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user