Skip to content

Commit 09b4bc0

Browse files
author
Deepika
committed
This is the initial version of stats implementation in network layer.
SocketStats Class is added to collect and provide the statistics information. In this phase only socket information is collected and max sockets that can be recorded at any time are configurable through 'MBED_CONF_NSAPI_SOCKET_STATS_MAX_COUNT' Network statistics can be enabled through a macro MBED_NW_STATS_ENABLED More information on design is captured in #8743
1 parent d5da9eb commit 09b4bc0

File tree

10 files changed

+342
-5
lines changed

10 files changed

+342
-5
lines changed

features/netsocket/InternetSocket.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "rtos/EventFlags.h"
2727
#include "Callback.h"
2828
#include "mbed_toolchain.h"
29+
#include "SocketStats.h"
2930

3031
/** Socket implementation that uses IP network stack.
3132
* Not to be directly used by applications. Cannot be directly instantiated.
@@ -176,6 +177,7 @@ class InternetSocket : public Socket {
176177
static const int FINISHED_FLAG = 0x3u;
177178

178179
friend class DTLSSocket; // Allow DTLSSocket::connect() to do name resolution on the _stack
180+
SocketStats _socket_stats;
179181

180182
#endif //!defined(DOXYGEN_ONLY)
181183
};

features/netsocket/SocketStats.cpp

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2018 ARM Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "SocketStats.h"
18+
#include "platform/mbed_error.h"
19+
#include "platform/mbed_assert.h"
20+
#ifdef MBED_CONF_RTOS_PRESENT
21+
#include "rtos/Kernel.h"
22+
#endif
23+
24+
#include <string.h>
25+
#include <stdlib.h>
26+
27+
#if defined(MBED_NW_STATS_ENABLED)
28+
SingletonPtr<PlatformMutex> SocketStats::_mutex;
29+
mbed_stats_socket_t SocketStats::_stats[MBED_CONF_NSAPI_SOCKET_STATS_MAX_COUNT] = {0};
30+
uint32_t SocketStats::_size = 0;
31+
32+
int SocketStats::get_entry_position(const Socket *const reference_id)
33+
{
34+
_mutex->lock();
35+
for (uint32_t j = 0; j < _size; j++) {
36+
if (_stats[j].reference_id == reference_id) {
37+
return j;
38+
}
39+
}
40+
return -1;
41+
}
42+
#endif
43+
44+
size_t SocketStats::mbed_stats_socket_get_each(mbed_stats_socket_t *stats, size_t count)
45+
{
46+
MBED_ASSERT(stats != NULL);
47+
size_t i = 0;
48+
#if defined(MBED_NW_STATS_ENABLED)
49+
memset(stats, 0, count * sizeof(mbed_stats_socket_t));
50+
_mutex->lock();
51+
for (uint32_t j = 0; j < count; j++) {
52+
if (_stats[j].reference_id) {
53+
memcpy(&stats[i], &_stats[j], sizeof(mbed_stats_socket_t));
54+
i++;
55+
}
56+
}
57+
_mutex->unlock();
58+
#endif
59+
return i;
60+
}
61+
62+
SocketStats::SocketStats()
63+
{
64+
}
65+
66+
void SocketStats::stats_new_socket_entry(const Socket *const reference_id)
67+
{
68+
#if defined(MBED_NW_STATS_ENABLED)
69+
_mutex->lock();
70+
if (get_entry_position(reference_id) >= 0) {
71+
// Duplicate entry
72+
MBED_WARNING1(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STATS, MBED_ERROR_CODE_INVALID_INDEX), "Duplicate socket Reference ID ", reference_id);
73+
} else if (_size <= MBED_CONF_NSAPI_SOCKET_STATS_MAX_COUNT) {
74+
// Add new entry
75+
_stats[_size].reference_id = (Socket *)reference_id;
76+
_size++;
77+
} else {
78+
int position = -1;
79+
uint64_t oldest_time = 0;
80+
// Determine which entry in the list shall be over-written
81+
for (uint32_t j = 0; j < MBED_CONF_NSAPI_SOCKET_STATS_MAX_COUNT; j++) {
82+
if (SOCK_CLOSED == _stats[j].state) {
83+
if ((0 == oldest_time) || (oldest_time < _stats[j].last_change_tick)) {
84+
oldest_time = _stats[j].last_change_tick;
85+
position = j;
86+
}
87+
}
88+
}
89+
if (-1 == position) {
90+
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STATS, MBED_ERROR_CODE_OUT_OF_RESOURCES), "List full with all open sockets");
91+
}
92+
memset(&_stats[position], 0, sizeof(mbed_stats_socket_t));
93+
_stats[position].reference_id = (Socket *)reference_id;
94+
}
95+
_mutex->unlock();
96+
#endif
97+
return;
98+
}
99+
100+
void SocketStats::stats_update_socket_state(const Socket *const reference_id, socket_state state)
101+
{
102+
#if defined(MBED_NW_STATS_ENABLED)
103+
_mutex->lock();
104+
int position = get_entry_position(reference_id);
105+
if (position >= 0) {
106+
_stats[position].state = state;
107+
#ifdef MBED_CONF_RTOS_PRESENT
108+
_stats[position].last_change_tick = rtos::Kernel::get_ms_count();
109+
#endif
110+
}
111+
_mutex->unlock();
112+
#endif
113+
}
114+
115+
void SocketStats::stats_update_peer(const Socket *const reference_id, const SocketAddress &peer)
116+
{
117+
#if defined(MBED_NW_STATS_ENABLED)
118+
_mutex->lock();
119+
int position = get_entry_position(reference_id);
120+
if (position >= 0) {
121+
if (!_stats[position].peer) {
122+
_stats[position].peer = peer;
123+
}
124+
}
125+
_mutex->unlock();
126+
#endif
127+
}
128+
129+
void SocketStats::stats_update_proto(const Socket *const reference_id, nsapi_protocol_t proto)
130+
{
131+
#if defined(MBED_NW_STATS_ENABLED)
132+
_mutex->lock();
133+
int position = get_entry_position(reference_id);
134+
if (position >= 0) {
135+
_stats[position].proto = proto;
136+
}
137+
_mutex->unlock();
138+
#endif
139+
}
140+
141+
void SocketStats::stats_update_sent_bytes(const Socket *const reference_id, size_t sent_bytes)
142+
{
143+
#if defined(MBED_NW_STATS_ENABLED)
144+
_mutex->lock();
145+
int position = get_entry_position(reference_id);
146+
if (position >= 0) {
147+
_stats[position].sent_bytes += sent_bytes;
148+
}
149+
_mutex->unlock();
150+
#endif
151+
}
152+
153+
void SocketStats::stats_update_recv_bytes(const Socket *const reference_id, size_t recv_bytes)
154+
{
155+
#if defined(MBED_NW_STATS_ENABLED)
156+
_mutex->lock();
157+
int position = get_entry_position(reference_id);
158+
if (position >= 0) {
159+
_stats[position].recv_bytes += recv_bytes;
160+
}
161+
_mutex->unlock();
162+
#endif
163+
}

features/netsocket/SocketStats.h

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2018 ARM Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef SOCKET_STATS_H
18+
#define SOCKET_STATS_H
19+
20+
#include "platform/mbed_stats.h"
21+
#include "platform/SingletonPtr.h"
22+
#include "platform/PlatformMutex.h"
23+
#include "netsocket/Socket.h"
24+
#include "SocketAddress.h"
25+
#include "hal/ticker_api.h"
26+
27+
#ifndef MBED_CONF_NSAPI_SOCKET_STATS_MAX_COUNT
28+
#define MBED_CONF_NSAPI_SOCKET_STATS_MAX_COUNT 10
29+
#endif
30+
31+
typedef enum {
32+
SOCK_CLOSED, /**< Socket is closed and does not exist anymore in the system */
33+
SOCK_OPEN, /**< Socket is open, but not associated to any peer address */
34+
SOCK_CONNECTED, /**< Socket is associated to peer address, either by connect() or sendto()/recvfrom() calls */
35+
SOCK_LISTEN, /**< Socket is listening for incoming connections */
36+
}socket_state;
37+
38+
typedef struct {
39+
Socket *reference_id; /**< Used for identifying socket */
40+
SocketAddress peer; /**< Last associated peername of this socket (Destination address) */
41+
socket_state state; /**< State of this socket */
42+
nsapi_protocol_t proto; /**< Specifies a protocol used with socket */
43+
size_t sent_bytes; /**< Data sent through this socket */
44+
size_t recv_bytes; /**< Data received through this socket */
45+
us_timestamp_t last_change_tick;/**< osKernelGetTick() when state last changed */
46+
} mbed_stats_socket_t;
47+
48+
/** SocketStats class
49+
*
50+
*
51+
*/
52+
class SocketStats
53+
{
54+
public:
55+
SocketStats();
56+
virtual ~SocketStats()
57+
{
58+
}
59+
60+
/**
61+
* Fill the passed array of structures with the socket statistics for each created socket.
62+
*
63+
* @param stats A pointer to an array of mbed_stats_socket_t structures to fill
64+
* @param count The number of mbed_stats_socket_t structures in the provided array
65+
* @return The number of mbed_stats_socket_t structures that have been filled.
66+
* If the number of sockets on the system is less than or equal to count,
67+
* it will equal the number of sockets created (active / closed).
68+
* If the number of sockets on the system is greater than count,
69+
* it will equal count.
70+
*/
71+
static size_t mbed_stats_socket_get_each(mbed_stats_socket_t *stats, size_t count);
72+
73+
/** Add entry of newly created socket in statistics array.
74+
@Note: Entry in the array will be maintained even after socket is closed.
75+
It will be over-written for closed sockets when socket entries in
76+
`MBED_CONF_NSAPI_SOCKET_STATS_MAX_COUNT` exceed.
77+
*/
78+
void stats_new_socket_entry(const Socket *const reference_id);
79+
80+
/** Updates the state of socket and along with that records tick_last_change */
81+
void stats_update_socket_state(const Socket *const reference_id, socket_state state);
82+
83+
/** Update the peer information of the socket */
84+
void stats_update_peer(const Socket *const reference_id, const SocketAddress &peer);
85+
86+
/** Update socket protocol */
87+
void stats_update_proto(const Socket *const reference_id, nsapi_protocol_t proto);
88+
89+
/** Update bytes sent on socket, which is cumulative count per socket */
90+
void stats_update_sent_bytes(const Socket *const reference_id, size_t sent_bytes);
91+
92+
/** Update bytes received on socket, which is cumulative count per socket */
93+
void stats_update_recv_bytes(const Socket *const reference_id, size_t recv_bytes);
94+
95+
#if defined(MBED_NW_STATS_ENABLED)
96+
private:
97+
static mbed_stats_socket_t _stats[MBED_CONF_NSAPI_SOCKET_STATS_MAX_COUNT];
98+
static SingletonPtr<PlatformMutex> _mutex;
99+
static uint32_t _size;
100+
101+
/** Internal function to scan the array and get position of element in the list.
102+
This API locks the mutex and next API updating the entry in array
103+
should release the lock */
104+
int get_entry_position(const Socket *const reference_id);
105+
#endif
106+
};
107+
108+
#endif

features/netsocket/TCPServer.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@ using mbed::Callback;
2020

2121
TCPServer::TCPServer()
2222
{
23+
_socket_stats.stats_new_socket_entry(this);
2324
}
2425

2526
TCPServer::~TCPServer()
2627
{
28+
_socket_stats.stats_update_socket_state(this, SOCK_CLOSED);
2729
}
2830

2931
nsapi_error_t TCPServer::accept(TCPSocket *connection, SocketAddress *address)
@@ -52,7 +54,8 @@ nsapi_error_t TCPServer::accept(TCPSocket *connection, SocketAddress *address)
5254
connection->_socket = socket;
5355
connection->_event = Callback<void()>(connection, &TCPSocket::event);
5456
_stack->socket_attach(socket, &Callback<void()>::thunk, &connection->_event);
55-
57+
_socket_stats.stats_update_peer(this, *address);
58+
_socket_stats.stats_update_socket_state(this, SOCK_OPEN);
5659
connection->_lock.unlock();
5760
break;
5861
} else if ((_timeout == 0) || (ret != NSAPI_ERROR_WOULD_BLOCK)) {

features/netsocket/TCPSocket.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
TCPSocket::TCPSocket()
2222
{
23+
_socket_stats.stats_new_socket_entry(this);
2324
}
2425

2526
TCPSocket::TCPSocket(TCPSocket *parent, nsapi_socket_t socket, SocketAddress address)
@@ -28,17 +29,26 @@ TCPSocket::TCPSocket(TCPSocket *parent, nsapi_socket_t socket, SocketAddress add
2829
_stack = parent->_stack;
2930
_factory_allocated = true;
3031
_remote_peer = address;
31-
32+
_socket_stats.stats_new_socket_entry(this);
3233
_event = mbed::Callback<void()>(this, &TCPSocket::event);
3334
_stack->socket_attach(socket, &mbed::Callback<void()>::thunk, &_event);
3435
}
3536

3637
TCPSocket::~TCPSocket()
3738
{
39+
_socket_stats.stats_update_socket_state(this, SOCK_CLOSED);
40+
}
41+
42+
nsapi_error_t TCPSocket::close()
43+
{
44+
_socket_stats.stats_update_socket_state(this, SOCK_CLOSED);
45+
return InternetSocket::close();
3846
}
3947

4048
nsapi_protocol_t TCPSocket::get_proto()
4149
{
50+
_socket_stats.stats_update_proto(this, NSAPI_TCP);
51+
_socket_stats.stats_update_socket_state(this, SOCK_OPEN);
4252
return NSAPI_TCP;
4353
}
4454

@@ -64,6 +74,7 @@ nsapi_error_t TCPSocket::connect(const SocketAddress &address)
6474
_pending = 0;
6575
ret = _stack->socket_connect(_socket, address);
6676
if ((_timeout == 0) || !(ret == NSAPI_ERROR_IN_PROGRESS || ret == NSAPI_ERROR_ALREADY)) {
77+
_socket_stats.stats_update_socket_state(this, SOCK_CONNECTED);
6778
break;
6879
} else {
6980
blocking_connect_in_progress = true;
@@ -89,11 +100,13 @@ nsapi_error_t TCPSocket::connect(const SocketAddress &address)
89100

90101
/* Non-blocking connect gives "EISCONN" once done - convert to OK for blocking mode if we became connected during this call */
91102
if (ret == NSAPI_ERROR_IS_CONNECTED && blocking_connect_in_progress) {
103+
_socket_stats.stats_update_socket_state(this, SOCK_CONNECTED);
92104
ret = NSAPI_ERROR_OK;
93105
}
94106

95107
if (ret == NSAPI_ERROR_OK || ret == NSAPI_ERROR_IN_PROGRESS) {
96108
_remote_peer = address;
109+
_socket_stats.stats_update_peer(this, _remote_peer);
97110
}
98111

99112
_lock.unlock();
@@ -178,6 +191,7 @@ nsapi_size_or_error_t TCPSocket::send(const void *data, nsapi_size_t size)
178191
} else if (written == 0) {
179192
return NSAPI_ERROR_WOULD_BLOCK;
180193
} else {
194+
_socket_stats.stats_update_sent_bytes(this, written);
181195
return written;
182196
}
183197
}
@@ -208,6 +222,7 @@ nsapi_size_or_error_t TCPSocket::recv(void *data, nsapi_size_t size)
208222
_pending = 0;
209223
ret = _stack->socket_recv(_socket, data, size);
210224
if ((_timeout == 0) || (ret != NSAPI_ERROR_WOULD_BLOCK)) {
225+
_socket_stats.stats_update_recv_bytes(this, ret);
211226
break;
212227
} else {
213228
uint32_t flag;
@@ -252,6 +267,9 @@ nsapi_error_t TCPSocket::listen(int backlog)
252267
ret = NSAPI_ERROR_NO_SOCKET;
253268
} else {
254269
ret = _stack->socket_listen(_socket, backlog);
270+
if (NSAPI_ERROR_OK == ret) {
271+
_socket_stats.stats_update_socket_state(this, SOCK_LISTEN);
272+
}
255273
}
256274

257275
_lock.unlock();

0 commit comments

Comments
 (0)