From ddd0704b76ca302849655220cddb3499ebab0b56 Mon Sep 17 00:00:00 2001 From: pvanhorn Date: Thu, 13 Oct 2016 17:32:16 -0700 Subject: [PATCH] Allow for multiple callers to otSetStateChangeCallback. (#811) * Allow for multiple callers to otSetStateChangeCallback. --- include/openthread.h | 15 +++++++- src/core/net/netif.cpp | 29 +++++++++++++++ src/core/net/netif.hpp | 43 +++++++++++++++++++++++ src/core/openthread-core-default-config.h | 11 ++++++ src/core/openthread-instance.h | 3 +- src/core/openthread.cpp | 30 ++++++++++++++-- 6 files changed, 126 insertions(+), 5 deletions(-) diff --git a/include/openthread.h b/include/openthread.h index 14bd1c738..70fe2c64d 100644 --- a/include/openthread.h +++ b/include/openthread.h @@ -868,8 +868,21 @@ typedef void (*otStateChangedCallback)(uint32_t aFlags, void *aContext); * @param[in] aCallback A pointer to a function that is called with certain configuration or state changes. * @param[in] aContext A pointer to application-specific context. * + * @retval kThreadError_None Added the callback to the list of callbacks. + * @retval kThreadError_NoBufs Could not add the callback due to resource constraints. + * */ -void otSetStateChangedCallback(otInstance *aInstance, otStateChangedCallback aCallback, void *aContext); +ThreadError otSetStateChangedCallback(otInstance *aInstance, otStateChangedCallback aCallback, void *aContext); + +/** + * This function removes a callback to indicate when certain configuration or state changes within OpenThread. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aCallback A pointer to a function that is called with certain configuration or state changes. + * @param[in] aContext A pointer to application-specific context. + * + */ +void otRemoveStateChangeCallback(otInstance *aInstance, otStateChangedCallback aCallback, void *aCallbackContext); /** * This function gets the Active Operational Dataset. diff --git a/src/core/net/netif.cpp b/src/core/net/netif.cpp index 91da882f6..bca76470a 100644 --- a/src/core/net/netif.cpp +++ b/src/core/net/netif.cpp @@ -74,6 +74,35 @@ exit: return error; } +ThreadError Netif::RemoveCallback(NetifCallback &aCallback) +{ + ThreadError error = kThreadError_Already; + NetifCallback *prev = NULL; + + for (NetifCallback *cur = mCallbacks; cur; cur = cur->mNext) + { + if (cur == &aCallback) + { + if (prev) + { + prev->mNext = cur->mNext; + } + else + { + mCallbacks = mCallbacks->mNext; + } + + cur->mNext = NULL; + error = kThreadError_None; + break; + } + + prev = cur; + } + + return error; +} + Netif *Netif::GetNext() const { return mNext; diff --git a/src/core/net/netif.hpp b/src/core/net/netif.hpp index 07e87bf09..826161f00 100644 --- a/src/core/net/netif.hpp +++ b/src/core/net/netif.hpp @@ -176,6 +176,39 @@ public: mContext = aContext; } + /** + * This method tests whether the object is free or in use. + * + * @returns True if the object is free, false otherwise. + * + */ + bool IsFree(void) { + return (mCallback == NULL); + } + + /** + * This method frees the object. + * + */ + void Free(void) { + mCallback = NULL; + mContext = NULL; + mNext = NULL; + } + + /** + * This method tests whether the object is set to the provided elements. + * + * @param[in] aCallback A pointer to a function that is called when configuration or state changes. + * @param[in] aContext A pointer to arbitrary context information. + * + * @returns True if the object elements equal the input params, false otherwise. + * + */ + bool IsServing(otStateChangedCallback aCallback, void *aContext) { + return (aCallback == mCallback && aContext == mContext); + } + private: void Callback(uint32_t aFlags) { if (mCallback != NULL) { @@ -347,6 +380,16 @@ public: */ ThreadError RegisterCallback(NetifCallback &aCallback); + /** + * This method removes a network interface callback. + * + * @param[in] aCallback A reference to the callback. + * + * @retval kThreadError_None Successfully removed the callback. + * @retval kThreadError_Already The callback was not in the list. + */ + ThreadError RemoveCallback(NetifCallback &aCallback); + /** * This method indicates whether or not a state changed callback is pending. * diff --git a/src/core/openthread-core-default-config.h b/src/core/openthread-core-default-config.h index 89b615755..0a52a099a 100644 --- a/src/core/openthread-core-default-config.h +++ b/src/core/openthread-core-default-config.h @@ -185,6 +185,17 @@ #define OPENTHREAD_CONFIG_MAX_JOINER_ENTRIES 2 #endif // OPENTHREAD_CONFIG_MAX_JOINER_ENTRIES +/** + * @def OPENTHREAD_CONFIG_NUM_MESSAGE_BUFFERS + * + * The number of message buffers in the buffer pool. + * + */ +#ifndef OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS +#define OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS 1 +#endif // OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS + + /** * @def OPENTHREAD_CONFIG_LOG_LEVEL * diff --git a/src/core/openthread-instance.h b/src/core/openthread-instance.h index abc0e9972..5dd0124bf 100644 --- a/src/core/openthread-instance.h +++ b/src/core/openthread-instance.h @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -52,7 +53,7 @@ typedef struct otInstance // Callbacks // - Thread::Ip6::NetifCallback mNetifCallback; + Thread::Ip6::NetifCallback mNetifCallback[OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS]; otReceiveIp6DatagramCallback mReceiveIp6DatagramCallback; void *mReceiveIp6DatagramCallbackContext; diff --git a/src/core/openthread.cpp b/src/core/openthread.cpp index cff550c21..f70627c01 100644 --- a/src/core/openthread.cpp +++ b/src/core/openthread.cpp @@ -925,10 +925,34 @@ ThreadError otCreateSemanticallyOpaqueIid(otInstance *aInstance, otNetifAddress return static_cast(aContext)->CreateIid(aInstance, aAddress); } -void otSetStateChangedCallback(otInstance *aInstance, otStateChangedCallback aCallback, void *aCallbackContext) +ThreadError otSetStateChangedCallback(otInstance *aInstance, otStateChangedCallback aCallback, void *aCallbackContext) { - aInstance->mNetifCallback.Set(aCallback, aCallbackContext); - aInstance->mThreadNetif.RegisterCallback(aInstance->mNetifCallback); + ThreadError error = kThreadError_NoBufs; + + for (size_t i = 0; i < OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS; i++) + { + if (aInstance->mNetifCallback[i].IsFree()) + { + aInstance->mNetifCallback[i].Set(aCallback, aCallbackContext); + error = aInstance->mThreadNetif.RegisterCallback(aInstance->mNetifCallback[i]); + break; + } + } + + return error; +} + +void otRemoveStateChangeCallback(otInstance *aInstance, otStateChangedCallback aCallback, void *aCallbackContext) +{ + for (size_t i = 0; i < OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS; i++) + { + if (aInstance->mNetifCallback[i].IsServing(aCallback, aCallbackContext)) + { + aInstance->mThreadNetif.RemoveCallback(aInstance->mNetifCallback[i]); + aInstance->mNetifCallback[i].Free(); + break; + } + } } const char *otGetVersionString(void)