mirror of https://github.com/ARMmbed/mbed-os.git
Allow multiple network status listeners
Allow more than one callback to be register to NetworkInterfaces. This introduces new APIs: void NetworkInterface::add_event_listener(...); void NetworkInterface::remove_event_listener(...); Which internally calls interfaces attach() functions.pull/9424/head
parent
a4ed473afc
commit
9c98d1572b
|
|
@ -17,7 +17,8 @@ set(unittest-sources
|
|||
../features/frameworks/nanostack-libservice/source/libip6string/ip6tos.c
|
||||
../features/frameworks/nanostack-libservice/source/libip4string/stoip4.c
|
||||
../features/frameworks/nanostack-libservice/source/libip6string/stoip6.c
|
||||
../features/frameworks/nanostack-libservice/source/libBits/common_functions.c
|
||||
../features/frameworks/nanostack-libservice/source/libBits/common_functions.c
|
||||
../features/frameworks/nanostack-libservice/source/libList/ns_list.c
|
||||
)
|
||||
|
||||
# Test files
|
||||
|
|
@ -34,4 +35,5 @@ set(unittest-test-sources
|
|||
stubs/ip4tos_stub.c
|
||||
stubs/NetworkStack_stub.cpp
|
||||
stubs/SocketStats_Stub.cpp
|
||||
stubs/mbed_error.c
|
||||
)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include "NetworkStack_stub.h"
|
||||
|
||||
class stubNetworkInterface : public NetworkInterface {
|
||||
public:
|
||||
virtual nsapi_error_t connect()
|
||||
{
|
||||
return NSAPI_ERROR_OK;
|
||||
|
|
@ -32,13 +33,22 @@ class stubNetworkInterface : public NetworkInterface {
|
|||
{
|
||||
return &stack;
|
||||
};
|
||||
public:
|
||||
virtual void attach(mbed::Callback<void(nsapi_event_t, intptr_t)> cb)
|
||||
{
|
||||
status_cb = cb;
|
||||
}
|
||||
void event(nsapi_event_t e, intptr_t i)
|
||||
{
|
||||
status_cb(e, i);
|
||||
}
|
||||
private:
|
||||
mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb;
|
||||
NetworkStackstub stack;
|
||||
};
|
||||
|
||||
class TestNetworkInterface : public testing::Test {
|
||||
protected:
|
||||
NetworkInterface *iface;
|
||||
stubNetworkInterface *iface;
|
||||
|
||||
virtual void SetUp()
|
||||
{
|
||||
|
|
@ -131,4 +141,70 @@ TEST_F(TestNetworkInterface, set_blocking)
|
|||
EXPECT_EQ(iface->set_blocking(true), NSAPI_ERROR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
// No way to test attach as it doesn't do or return anything.
|
||||
void my_iface_callback(nsapi_event_t e, intptr_t i)
|
||||
{
|
||||
(void)e;
|
||||
(void)i;
|
||||
callback_is_called = true;
|
||||
}
|
||||
static bool second_callback_called;
|
||||
void my_iface_callback2(nsapi_event_t e, intptr_t i)
|
||||
{
|
||||
(void)e;
|
||||
(void)i;
|
||||
second_callback_called = true;
|
||||
}
|
||||
|
||||
TEST_F(TestNetworkInterface, add_event_listener)
|
||||
{
|
||||
callback_is_called = false;
|
||||
second_callback_called = false;
|
||||
iface->add_event_listener(my_iface_callback);
|
||||
iface->event(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, 0);
|
||||
EXPECT_EQ(callback_is_called, true);
|
||||
|
||||
iface->remove_event_listener(my_iface_callback);
|
||||
}
|
||||
|
||||
TEST_F(TestNetworkInterface, remove_event_listener)
|
||||
{
|
||||
callback_is_called = false;
|
||||
second_callback_called = false;
|
||||
iface->add_event_listener(my_iface_callback);
|
||||
iface->add_event_listener(my_iface_callback2);
|
||||
iface->event(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, 0);
|
||||
EXPECT_EQ(callback_is_called, true);
|
||||
EXPECT_EQ(second_callback_called, true);
|
||||
|
||||
iface->remove_event_listener(my_iface_callback2);
|
||||
callback_is_called = false;
|
||||
second_callback_called = false;
|
||||
|
||||
iface->event(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, 0);
|
||||
EXPECT_EQ(callback_is_called, true);
|
||||
EXPECT_EQ(second_callback_called, false);
|
||||
|
||||
iface->remove_event_listener(my_iface_callback);
|
||||
}
|
||||
|
||||
TEST_F(TestNetworkInterface, correct_event_listener_per_interface)
|
||||
{
|
||||
stubNetworkInterface *iface2 = new stubNetworkInterface();
|
||||
iface->add_event_listener(my_iface_callback);
|
||||
iface2->add_event_listener(my_iface_callback2);
|
||||
|
||||
callback_is_called = false;
|
||||
second_callback_called = false;
|
||||
iface->event(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, 0);
|
||||
EXPECT_EQ(callback_is_called, true);
|
||||
EXPECT_EQ(second_callback_called, false);
|
||||
|
||||
callback_is_called = false;
|
||||
second_callback_called = false;
|
||||
iface2->event(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, 0);
|
||||
EXPECT_EQ(callback_is_called, false);
|
||||
EXPECT_EQ(second_callback_called, true);
|
||||
|
||||
iface->remove_event_listener(my_iface_callback);
|
||||
iface2->remove_event_listener(my_iface_callback2);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ set(unittest-sources
|
|||
../features/frameworks/nanostack-libservice/source/libip6string/ip6tos.c
|
||||
../features/frameworks/nanostack-libservice/source/libip4string/stoip4.c
|
||||
../features/frameworks/nanostack-libservice/source/libip6string/stoip6.c
|
||||
../features/frameworks/nanostack-libservice/source/libBits/common_functions.c
|
||||
../features/frameworks/nanostack-libservice/source/libBits/common_functions.c
|
||||
../features/frameworks/nanostack-libservice/source/libList/ns_list.c
|
||||
)
|
||||
|
||||
# Test files
|
||||
|
|
@ -26,4 +27,5 @@ set(unittest-test-sources
|
|||
stubs/EventFlags_stub.cpp
|
||||
features/netsocket/NetworkInterface/test_NetworkInterface.cpp
|
||||
stubs/SocketStats_Stub.cpp
|
||||
stubs/mbed_error.c
|
||||
)
|
||||
|
|
|
|||
|
|
@ -87,3 +87,6 @@ nsapi_error_t NetworkInterface::gethostbyname_async_cancel(int id)
|
|||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
NetworkInterface::~NetworkInterface()
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
|
||||
int mbed_error(int error_status, const char *error_msg, unsigned int error_value, const char *filename, int line_number)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -16,7 +16,10 @@
|
|||
|
||||
#include "netsocket/NetworkInterface.h"
|
||||
#include "netsocket/NetworkStack.h"
|
||||
#include "platform/Callback.h"
|
||||
#include "platform/mbed_error.h"
|
||||
#include <string.h>
|
||||
#include "ns_list.h"
|
||||
|
||||
|
||||
// Default network-interface state
|
||||
|
|
@ -75,8 +78,64 @@ nsapi_error_t NetworkInterface::add_dns_server(const SocketAddress &address)
|
|||
return get_stack()->add_dns_server(address);
|
||||
}
|
||||
|
||||
void NetworkInterface::attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb)
|
||||
typedef struct iface_eventlist_entry {
|
||||
NetworkInterface *iface;
|
||||
mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb;
|
||||
ns_list_link_t link;
|
||||
} iface_eventlist_entry_t;
|
||||
|
||||
typedef NS_LIST_HEAD(iface_eventlist_entry_t, link) iface_eventlist_t;
|
||||
|
||||
static iface_eventlist_t *get_interface_event_list_head()
|
||||
{
|
||||
static iface_eventlist_t NS_LIST_NAME_INIT(event_list);
|
||||
return &event_list;
|
||||
}
|
||||
|
||||
static void call_all_event_listeners(NetworkInterface *iface, nsapi_event_t event, intptr_t val)
|
||||
{
|
||||
iface_eventlist_t *event_list = get_interface_event_list_head();
|
||||
ns_list_foreach(iface_eventlist_entry_t, entry, event_list) {
|
||||
if (entry->iface == iface) {
|
||||
entry->status_cb(event, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkInterface::add_event_listener(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb)
|
||||
{
|
||||
iface_eventlist_t *event_list = get_interface_event_list_head();
|
||||
iface_eventlist_entry_t *entry = new (std::nothrow) iface_eventlist_entry_t;
|
||||
if (!entry) {
|
||||
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STACK, MBED_ERROR_CODE_ENOMEM), "Failed to allocate entry");
|
||||
return;
|
||||
}
|
||||
entry->iface = this;
|
||||
entry->status_cb = status_cb;
|
||||
ns_list_add_to_end(event_list, entry);
|
||||
attach(mbed::callback(&call_all_event_listeners, this));
|
||||
}
|
||||
|
||||
void NetworkInterface::remove_event_listener(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb)
|
||||
{
|
||||
iface_eventlist_t *event_list = get_interface_event_list_head();
|
||||
ns_list_foreach_safe(iface_eventlist_entry_t, entry, event_list) {
|
||||
if (entry->status_cb == status_cb && entry->iface == this) {
|
||||
ns_list_remove(event_list, entry);
|
||||
delete entry;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NetworkInterface::~NetworkInterface()
|
||||
{
|
||||
iface_eventlist_t *event_list = get_interface_event_list_head();
|
||||
ns_list_foreach_safe(iface_eventlist_entry_t, entry, event_list) {
|
||||
if (entry->iface == this) {
|
||||
ns_list_remove(event_list, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsapi_connection_status_t NetworkInterface::get_connection_status() const
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class EMACInterface;
|
|||
class NetworkInterface: public DNS {
|
||||
public:
|
||||
|
||||
virtual ~NetworkInterface() {};
|
||||
virtual ~NetworkInterface();
|
||||
|
||||
/** Return the default network interface.
|
||||
*
|
||||
|
|
@ -241,11 +241,37 @@ public:
|
|||
*
|
||||
* The specified status callback function will be called on status changes
|
||||
* on the network. The parameters on the callback are the event type and
|
||||
* event-type dependent reason parameter.
|
||||
* event-type dependent reason parameter. Only one callback can be registered at a time.
|
||||
*
|
||||
* To unregister a callback call with status_cb parameter as a zero.
|
||||
*
|
||||
* *NOTE:* Any callbacks registered with this function will be overwritten if
|
||||
* add_event_listener() API is used.
|
||||
*
|
||||
* @param status_cb The callback for status changes.
|
||||
*/
|
||||
virtual void attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb);
|
||||
virtual void attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb) = 0;
|
||||
|
||||
/** Add event listener for interface.
|
||||
*
|
||||
* This API allows multiple callback to be registered for a single interface.
|
||||
* When first called, internal list of event handlers are created and registered to
|
||||
* interface through attach() API.
|
||||
*
|
||||
* Application may only use attach() or add_event_listener() interface. Mixing usage
|
||||
* of both leads to undefined behavior.
|
||||
*
|
||||
* @param status_cb The callback for status changes.
|
||||
*/
|
||||
void add_event_listener(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb);
|
||||
|
||||
/** Remove event listener from interface.
|
||||
*
|
||||
* Remove previously added callback from the handler list.
|
||||
*
|
||||
* @param status_cb The callback to unregister.
|
||||
*/
|
||||
void remove_event_listener(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb);
|
||||
|
||||
/** Get the connection status.
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in New Issue