Skip to content

Commit 9c98d15

Browse files
author
Seppo Takalo
committed
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.
1 parent a4ed473 commit 9c98d15

File tree

7 files changed

+182
-9
lines changed

7 files changed

+182
-9
lines changed

UNITTESTS/features/netsocket/EthernetInterface/unittest.cmake

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ set(unittest-sources
1717
../features/frameworks/nanostack-libservice/source/libip6string/ip6tos.c
1818
../features/frameworks/nanostack-libservice/source/libip4string/stoip4.c
1919
../features/frameworks/nanostack-libservice/source/libip6string/stoip6.c
20-
../features/frameworks/nanostack-libservice/source/libBits/common_functions.c
20+
../features/frameworks/nanostack-libservice/source/libBits/common_functions.c
21+
../features/frameworks/nanostack-libservice/source/libList/ns_list.c
2122
)
2223

2324
# Test files
@@ -34,4 +35,5 @@ set(unittest-test-sources
3435
stubs/ip4tos_stub.c
3536
stubs/NetworkStack_stub.cpp
3637
stubs/SocketStats_Stub.cpp
38+
stubs/mbed_error.c
3739
)

UNITTESTS/features/netsocket/NetworkInterface/test_NetworkInterface.cpp

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "NetworkStack_stub.h"
2121

2222
class stubNetworkInterface : public NetworkInterface {
23+
public:
2324
virtual nsapi_error_t connect()
2425
{
2526
return NSAPI_ERROR_OK;
@@ -32,13 +33,22 @@ class stubNetworkInterface : public NetworkInterface {
3233
{
3334
return &stack;
3435
};
35-
public:
36+
virtual void attach(mbed::Callback<void(nsapi_event_t, intptr_t)> cb)
37+
{
38+
status_cb = cb;
39+
}
40+
void event(nsapi_event_t e, intptr_t i)
41+
{
42+
status_cb(e, i);
43+
}
44+
private:
45+
mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb;
3646
NetworkStackstub stack;
3747
};
3848

3949
class TestNetworkInterface : public testing::Test {
4050
protected:
41-
NetworkInterface *iface;
51+
stubNetworkInterface *iface;
4252

4353
virtual void SetUp()
4454
{
@@ -131,4 +141,70 @@ TEST_F(TestNetworkInterface, set_blocking)
131141
EXPECT_EQ(iface->set_blocking(true), NSAPI_ERROR_UNSUPPORTED);
132142
}
133143

134-
// No way to test attach as it doesn't do or return anything.
144+
void my_iface_callback(nsapi_event_t e, intptr_t i)
145+
{
146+
(void)e;
147+
(void)i;
148+
callback_is_called = true;
149+
}
150+
static bool second_callback_called;
151+
void my_iface_callback2(nsapi_event_t e, intptr_t i)
152+
{
153+
(void)e;
154+
(void)i;
155+
second_callback_called = true;
156+
}
157+
158+
TEST_F(TestNetworkInterface, add_event_listener)
159+
{
160+
callback_is_called = false;
161+
second_callback_called = false;
162+
iface->add_event_listener(my_iface_callback);
163+
iface->event(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, 0);
164+
EXPECT_EQ(callback_is_called, true);
165+
166+
iface->remove_event_listener(my_iface_callback);
167+
}
168+
169+
TEST_F(TestNetworkInterface, remove_event_listener)
170+
{
171+
callback_is_called = false;
172+
second_callback_called = false;
173+
iface->add_event_listener(my_iface_callback);
174+
iface->add_event_listener(my_iface_callback2);
175+
iface->event(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, 0);
176+
EXPECT_EQ(callback_is_called, true);
177+
EXPECT_EQ(second_callback_called, true);
178+
179+
iface->remove_event_listener(my_iface_callback2);
180+
callback_is_called = false;
181+
second_callback_called = false;
182+
183+
iface->event(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, 0);
184+
EXPECT_EQ(callback_is_called, true);
185+
EXPECT_EQ(second_callback_called, false);
186+
187+
iface->remove_event_listener(my_iface_callback);
188+
}
189+
190+
TEST_F(TestNetworkInterface, correct_event_listener_per_interface)
191+
{
192+
stubNetworkInterface *iface2 = new stubNetworkInterface();
193+
iface->add_event_listener(my_iface_callback);
194+
iface2->add_event_listener(my_iface_callback2);
195+
196+
callback_is_called = false;
197+
second_callback_called = false;
198+
iface->event(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, 0);
199+
EXPECT_EQ(callback_is_called, true);
200+
EXPECT_EQ(second_callback_called, false);
201+
202+
callback_is_called = false;
203+
second_callback_called = false;
204+
iface2->event(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, 0);
205+
EXPECT_EQ(callback_is_called, false);
206+
EXPECT_EQ(second_callback_called, true);
207+
208+
iface->remove_event_listener(my_iface_callback);
209+
iface2->remove_event_listener(my_iface_callback2);
210+
}

UNITTESTS/features/netsocket/NetworkInterface/unittest.cmake

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ set(unittest-sources
1212
../features/frameworks/nanostack-libservice/source/libip6string/ip6tos.c
1313
../features/frameworks/nanostack-libservice/source/libip4string/stoip4.c
1414
../features/frameworks/nanostack-libservice/source/libip6string/stoip6.c
15-
../features/frameworks/nanostack-libservice/source/libBits/common_functions.c
15+
../features/frameworks/nanostack-libservice/source/libBits/common_functions.c
16+
../features/frameworks/nanostack-libservice/source/libList/ns_list.c
1617
)
1718

1819
# Test files
@@ -26,4 +27,5 @@ set(unittest-test-sources
2627
stubs/EventFlags_stub.cpp
2728
features/netsocket/NetworkInterface/test_NetworkInterface.cpp
2829
stubs/SocketStats_Stub.cpp
30+
stubs/mbed_error.c
2931
)

UNITTESTS/stubs/NetworkInterface_stub.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,6 @@ nsapi_error_t NetworkInterface::gethostbyname_async_cancel(int id)
8787
return NSAPI_ERROR_UNSUPPORTED;
8888
}
8989

90+
NetworkInterface::~NetworkInterface()
91+
{
92+
}

UNITTESTS/stubs/mbed_error.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
int mbed_error(int error_status, const char *error_msg, unsigned int error_value, const char *filename, int line_number)
3+
{
4+
return 0;
5+
}

features/netsocket/NetworkInterface.cpp

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616

1717
#include "netsocket/NetworkInterface.h"
1818
#include "netsocket/NetworkStack.h"
19+
#include "platform/Callback.h"
20+
#include "platform/mbed_error.h"
1921
#include <string.h>
22+
#include "ns_list.h"
2023

2124

2225
// Default network-interface state
@@ -75,8 +78,64 @@ nsapi_error_t NetworkInterface::add_dns_server(const SocketAddress &address)
7578
return get_stack()->add_dns_server(address);
7679
}
7780

78-
void NetworkInterface::attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb)
81+
typedef struct iface_eventlist_entry {
82+
NetworkInterface *iface;
83+
mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb;
84+
ns_list_link_t link;
85+
} iface_eventlist_entry_t;
86+
87+
typedef NS_LIST_HEAD(iface_eventlist_entry_t, link) iface_eventlist_t;
88+
89+
static iface_eventlist_t *get_interface_event_list_head()
90+
{
91+
static iface_eventlist_t NS_LIST_NAME_INIT(event_list);
92+
return &event_list;
93+
}
94+
95+
static void call_all_event_listeners(NetworkInterface *iface, nsapi_event_t event, intptr_t val)
96+
{
97+
iface_eventlist_t *event_list = get_interface_event_list_head();
98+
ns_list_foreach(iface_eventlist_entry_t, entry, event_list) {
99+
if (entry->iface == iface) {
100+
entry->status_cb(event, val);
101+
}
102+
}
103+
}
104+
105+
void NetworkInterface::add_event_listener(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb)
79106
{
107+
iface_eventlist_t *event_list = get_interface_event_list_head();
108+
iface_eventlist_entry_t *entry = new (std::nothrow) iface_eventlist_entry_t;
109+
if (!entry) {
110+
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STACK, MBED_ERROR_CODE_ENOMEM), "Failed to allocate entry");
111+
return;
112+
}
113+
entry->iface = this;
114+
entry->status_cb = status_cb;
115+
ns_list_add_to_end(event_list, entry);
116+
attach(mbed::callback(&call_all_event_listeners, this));
117+
}
118+
119+
void NetworkInterface::remove_event_listener(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb)
120+
{
121+
iface_eventlist_t *event_list = get_interface_event_list_head();
122+
ns_list_foreach_safe(iface_eventlist_entry_t, entry, event_list) {
123+
if (entry->status_cb == status_cb && entry->iface == this) {
124+
ns_list_remove(event_list, entry);
125+
delete entry;
126+
return;
127+
}
128+
}
129+
}
130+
131+
NetworkInterface::~NetworkInterface()
132+
{
133+
iface_eventlist_t *event_list = get_interface_event_list_head();
134+
ns_list_foreach_safe(iface_eventlist_entry_t, entry, event_list) {
135+
if (entry->iface == this) {
136+
ns_list_remove(event_list, entry);
137+
}
138+
}
80139
}
81140

82141
nsapi_connection_status_t NetworkInterface::get_connection_status() const

features/netsocket/NetworkInterface.h

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class EMACInterface;
4343
class NetworkInterface: public DNS {
4444
public:
4545

46-
virtual ~NetworkInterface() {};
46+
virtual ~NetworkInterface();
4747

4848
/** Return the default network interface.
4949
*
@@ -241,11 +241,37 @@ class NetworkInterface: public DNS {
241241
*
242242
* The specified status callback function will be called on status changes
243243
* on the network. The parameters on the callback are the event type and
244-
* event-type dependent reason parameter.
244+
* event-type dependent reason parameter. Only one callback can be registered at a time.
245+
*
246+
* To unregister a callback call with status_cb parameter as a zero.
247+
*
248+
* *NOTE:* Any callbacks registered with this function will be overwritten if
249+
* add_event_listener() API is used.
250+
*
251+
* @param status_cb The callback for status changes.
252+
*/
253+
virtual void attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb) = 0;
254+
255+
/** Add event listener for interface.
256+
*
257+
* This API allows multiple callback to be registered for a single interface.
258+
* When first called, internal list of event handlers are created and registered to
259+
* interface through attach() API.
260+
*
261+
* Application may only use attach() or add_event_listener() interface. Mixing usage
262+
* of both leads to undefined behavior.
245263
*
246264
* @param status_cb The callback for status changes.
247265
*/
248-
virtual void attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb);
266+
void add_event_listener(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb);
267+
268+
/** Remove event listener from interface.
269+
*
270+
* Remove previously added callback from the handler list.
271+
*
272+
* @param status_cb The callback to unregister.
273+
*/
274+
void remove_event_listener(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb);
249275

250276
/** Get the connection status.
251277
*

0 commit comments

Comments
 (0)