Merge pull request #8592 from deepikabhavnani/nw_stats_ver2

Network Socket Statistics
pull/8798/head
Martin Kojtal 2018-11-27 09:03:49 +01:00 committed by GitHub
commit 2009f028b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 565 additions and 6 deletions

View File

@ -38,6 +38,10 @@ NetworkInterface *net;
Timer tc_bucket; // Timer to limit a test cases run time
}
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
mbed_stats_socket_t tcp_stats[MBED_CONF_NSAPI_SOCKET_STATS_MAX_COUNT];
#endif
char tcp_global::rx_buffer[RX_BUFF_SIZE];
char tcp_global::tx_buffer[TX_BUFF_SIZE];
@ -115,6 +119,13 @@ int split2half_rmng_tcp_test_time()
return (tcp_global::TESTS_TIMEOUT - tc_bucket.read()) / 2;
}
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
int fetch_stats()
{
return SocketStats::mbed_stats_socket_get_each(&tcp_stats[0], MBED_CONF_NSAPI_SOCKET_STATS_MAX_COUNT);
}
#endif
// Test setup
utest::v1::status_t greentea_setup(const size_t number_of_cases)
{

View File

@ -24,6 +24,11 @@ void fill_tx_buffer_ascii(char *buff, size_t len);
nsapi_error_t tcpsocket_connect_to_echo_srv(TCPSocket &sock);
nsapi_error_t tcpsocket_connect_to_discard_srv(TCPSocket &sock);
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
extern mbed_stats_socket_t tcp_stats[MBED_CONF_NSAPI_SOCKET_STATS_MAX_COUNT];
int fetch_stats(void);
#endif
/**
* Single testcase might take only half of the remaining execution time
*/

View File

@ -114,6 +114,13 @@ void tcpsocket_echotest_nonblock_receiver(void *receive_bytes)
void TCPSOCKET_ECHOTEST_NONBLOCK()
{
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
int j = 0;
int count = fetch_stats();
for (; j < count; j++) {
TEST_ASSERT_EQUAL(SOCK_CLOSED, tcp_stats[j].state);
}
#endif
tc_exec_time.start();
time_allotted = split2half_rmng_tcp_test_time(); // [s]
@ -160,6 +167,15 @@ void TCPSOCKET_ECHOTEST_NONBLOCK()
bytes2send -= sent;
}
printf("[Sender#%02d] bytes sent: %d\n", s_idx, pkt_s);
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
count = fetch_stats();
for (j = 0; j < count; j++) {
if ((tcp_stats[j].state == SOCK_OPEN) && (tcp_stats[j].proto == NSAPI_TCP)) {
break;
}
}
TEST_ASSERT_EQUAL(bytes2send, tcp_stats[j].sent_bytes);
#endif
tx_sem.wait(split2half_rmng_tcp_test_time());
thread->join();
delete thread;

View File

@ -26,6 +26,12 @@ using namespace utest::v1;
void TCPSOCKET_OPEN_CLOSE_REPEAT()
{
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
int count = fetch_stats();
for (int j = 0; j < count; j++) {
TEST_ASSERT_EQUAL(SOCK_CLOSED, tcp_stats[j].state);
}
#endif
TCPSocket *sock = new TCPSocket;
if (!sock) {
TEST_FAIL();
@ -36,4 +42,10 @@ void TCPSOCKET_OPEN_CLOSE_REPEAT()
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock->close());
}
delete sock;
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
count = fetch_stats();
for (int j = 0; j < count; j++) {
TEST_ASSERT_EQUAL(SOCK_CLOSED, tcp_stats[j].state);
}
#endif
}

View File

@ -70,6 +70,17 @@ void TCPSOCKET_OPEN_LIMIT()
break;
}
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
int count = fetch_stats();
int open_count = 0;
for (int j = 0; j < count; j++) {
if ((tcp_stats[j].state == SOCK_OPEN) && (tcp_stats[j].proto == NSAPI_TCP)) {
open_count++;
}
}
TEST_ASSERT(open_count >= 4);
#endif
TCPSocketItem *tmp;
for (TCPSocketItem *it = socket_list_head; it;) {
++open_sockets[i];

View File

@ -37,6 +37,10 @@ namespace {
NetworkInterface *net;
}
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
mbed_stats_socket_t udp_stats[MBED_CONF_NSAPI_SOCKET_STATS_MAX_COUNT];
#endif
NetworkInterface *get_interface()
{
return net;
@ -76,6 +80,13 @@ void fill_tx_buffer_ascii(char *buff, size_t len)
}
}
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
int fetch_stats()
{
return SocketStats::mbed_stats_socket_get_each(&udp_stats[0], MBED_CONF_NSAPI_SOCKET_STATS_MAX_COUNT);
}
#endif
// Test setup
utest::v1::status_t greentea_setup(const size_t number_of_cases)
{

View File

@ -22,6 +22,11 @@ NetworkInterface *get_interface();
void drop_bad_packets(UDPSocket &sock, int orig_timeout);
void fill_tx_buffer_ascii(char *buff, size_t len);
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
extern mbed_stats_socket_t udp_stats[MBED_CONF_NSAPI_SOCKET_STATS_MAX_COUNT];
int fetch_stats(void);
#endif
/*
* Test cases
*/

View File

@ -121,6 +121,14 @@ void udpsocket_echotest_nonblock_receiver(void *receive_bytes)
void UDPSOCKET_ECHOTEST_NONBLOCK()
{
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
int j = 0;
int count = fetch_stats();
for (; j < count; j++) {
TEST_ASSERT_EQUAL(SOCK_CLOSED, udp_stats[j].state);
}
#endif
SocketAddress udp_addr;
get_interface()->gethostbyname(MBED_CONF_APP_ECHO_SERVER_ADDR, &udp_addr);
udp_addr.set_port(MBED_CONF_APP_ECHO_SERVER_PORT);
@ -174,11 +182,27 @@ void UDPSOCKET_ECHOTEST_NONBLOCK()
}
}
free(stack_mem);
// Packet loss up to 30% tolerated
if (packets_sent > 0) {
double loss_ratio = 1 - ((double)packets_recv / (double)packets_sent);
printf("Packets sent: %d, packets received %d, loss ratio %.2lf\r\n", packets_sent, packets_recv, loss_ratio);
TEST_ASSERT_DOUBLE_WITHIN(TOLERATED_LOSS_RATIO, EXPECTED_LOSS_RATIO, loss_ratio);
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
count = fetch_stats();
for (j = 0; j < count; j++) {
if ((NSAPI_UDP == udp_stats[j].proto) && (SOCK_OPEN == udp_stats[j].state)) {
TEST_ASSERT(udp_stats[j].sent_bytes != 0);
TEST_ASSERT(udp_stats[j].recv_bytes != 0);
break;
}
}
loss_ratio = 1 - ((double)udp_stats[j].recv_bytes / (double)udp_stats[j].sent_bytes);
printf("Bytes sent: %d, bytes received %d, loss ratio %.2lf\r\n", udp_stats[j].sent_bytes, udp_stats[j].recv_bytes, loss_ratio);
TEST_ASSERT_DOUBLE_WITHIN(TOLERATED_LOSS_RATIO, EXPECTED_LOSS_RATIO, loss_ratio);
#endif
}
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.close());
}

View File

@ -26,6 +26,12 @@ using namespace utest::v1;
void UDPSOCKET_OPEN_CLOSE_REPEAT()
{
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
int count = fetch_stats();
for (int j = 0; j < count; j++) {
TEST_ASSERT_EQUAL(SOCK_CLOSED, udp_stats[j].state);
}
#endif
UDPSocket *sock = new UDPSocket;
if (!sock) {
TEST_FAIL();
@ -36,4 +42,10 @@ void UDPSOCKET_OPEN_CLOSE_REPEAT()
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock->close());
}
delete sock;
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
count = fetch_stats();
for (int j = 0; j < count; j++) {
TEST_ASSERT_EQUAL(SOCK_CLOSED, udp_stats[j].state);
}
#endif
}

View File

@ -21,6 +21,7 @@
#include "UDPSocket.h"
#include "unity/unity.h"
#include "utest.h"
#include "SocketStats.h"
using namespace utest::v1;
@ -69,7 +70,16 @@ void UDPSOCKET_OPEN_LIMIT()
if (!socket_list_head) {
break;
}
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
int count = fetch_stats();
int open_count = 0;
for (int j = 0; j < count; j++) {
if ((udp_stats[j].state == SOCK_OPEN) && (udp_stats[j].proto == NSAPI_UDP)) {
open_count++;
}
}
TEST_ASSERT(open_count >= 3);
#endif
UDPSocketItem *tmp;
for (UDPSocketItem *it = socket_list_head; it;) {
++open_sockets[i];

View File

@ -31,6 +31,7 @@ set(unittest-test-sources
stubs/stoip4_stub.c
stubs/ip4tos_stub.c
stubs/Kernel_stub.cpp
stubs/SocketStats_Stub.cpp
)
set(MBEDTLS_USER_CONFIG_FILE_PATH "\"../UNITTESTS/features/netsocket/DTLSSocket/dtls_test_config.h\"")

View File

@ -30,6 +30,7 @@ set(unittest-test-sources
stubs/stoip4_stub.c
stubs/ip4tos_stub.c
stubs/Kernel_stub.cpp
stubs/SocketStats_Stub.cpp
)
set(MBEDTLS_USER_CONFIG_FILE_PATH "\"../UNITTESTS/features/netsocket/DTLSSocketWrapper/dtls_test_config.h\"")

View File

@ -33,4 +33,5 @@ set(unittest-test-sources
stubs/stoip4_stub.c
stubs/ip4tos_stub.c
stubs/NetworkStack_stub.cpp
stubs/SocketStats_Stub.cpp
)

View File

@ -25,4 +25,5 @@ set(unittest-test-sources
stubs/EventFlags_stub.cpp
stubs/stoip4_stub.c
stubs/ip4tos_stub.c
stubs/SocketStats_Stub.cpp
)

View File

@ -25,4 +25,5 @@ set(unittest-test-sources
stubs/nsapi_dns_stub.cpp
stubs/EventFlags_stub.cpp
features/netsocket/NetworkInterface/test_NetworkInterface.cpp
stubs/SocketStats_Stub.cpp
)

View File

@ -28,4 +28,5 @@ set(unittest-test-sources
stubs/nsapi_dns_stub.cpp
stubs/EventFlags_stub.cpp
features/netsocket/NetworkStack/test_NetworkStack.cpp
stubs/SocketStats_Stub.cpp
)

View File

@ -28,4 +28,5 @@ set(unittest-test-sources
stubs/nsapi_dns_stub.cpp
stubs/EventFlags_stub.cpp
features/netsocket/TCPServer/test_TCPServer.cpp
stubs/SocketStats_Stub.cpp
)

View File

@ -26,4 +26,5 @@ set(unittest-test-sources
stubs/EventFlags_stub.cpp
stubs/stoip4_stub.c
stubs/ip4tos_stub.c
stubs/SocketStats_Stub.cpp
)

View File

@ -29,6 +29,7 @@ set(unittest-test-sources
stubs/EventFlags_stub.cpp
stubs/stoip4_stub.c
stubs/ip4tos_stub.c
stubs/SocketStats_Stub.cpp
)
set(MBEDTLS_USER_CONFIG_FILE_PATH "\"../UNITTESTS/features/netsocket/TLSSocket/tls_test_config.h\"")

View File

@ -28,6 +28,7 @@ set(unittest-test-sources
stubs/EventFlags_stub.cpp
stubs/stoip4_stub.c
stubs/ip4tos_stub.c
stubs/SocketStats_Stub.cpp
)
set(MBEDTLS_USER_CONFIG_FILE_PATH "\"../UNITTESTS/features/netsocket/TLSSocketWrapper/tls_test_config.h\"")

View File

@ -26,4 +26,5 @@ set(unittest-test-sources
stubs/nsapi_dns_stub.cpp
stubs/stoip4_stub.c
stubs/ip4tos_stub.c
stubs/SocketStats_Stub.cpp
)

View File

@ -0,0 +1,63 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "SocketStats.h"
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
int SocketStats::get_entry_position(const Socket *const reference_id)
{
return 0;
}
#endif
size_t SocketStats::mbed_stats_socket_get_each(mbed_stats_socket_t *stats, size_t count)
{
return 0;
}
SocketStats::SocketStats()
{
}
void SocketStats::stats_new_socket_entry(const Socket *const reference_id)
{
return;
}
void SocketStats::stats_update_socket_state(const Socket *const reference_id, socket_state state)
{
return;
}
void SocketStats::stats_update_peer(const Socket *const reference_id, const SocketAddress &peer)
{
return;
}
void SocketStats::stats_update_proto(const Socket *const reference_id, nsapi_protocol_t proto)
{
return;
}
void SocketStats::stats_update_sent_bytes(const Socket *const reference_id, size_t sent_bytes)
{
return;
}
void SocketStats::stats_update_recv_bytes(const Socket *const reference_id, size_t recv_bytes)
{
return;
}

View File

@ -450,7 +450,7 @@ private:
* @param func Callback to be called
* @return 0 on success, negative error code on failure
*/
nsapi_error_t call_in(int delay, mbed::Callback<void()> func);
virtual nsapi_error_t call_in(int delay, mbed::Callback<void()> func);
struct mbed_lwip_socket {
bool in_use;

View File

@ -24,6 +24,7 @@ InternetSocket::InternetSocket()
_readers(0), _writers(0), _pending(0),
_factory_allocated(false)
{
_socket_stats.stats_new_socket_entry(this);
}
InternetSocket::~InternetSocket()
@ -48,6 +49,7 @@ nsapi_error_t InternetSocket::open(NetworkStack *stack)
return err;
}
_socket_stats.stats_update_socket_state(this, SOCK_OPEN);
_socket = socket;
_event = callback(this, &InternetSocket::event);
_stack->socket_attach(_socket, Callback<void()>::thunk, &_event);
@ -72,7 +74,7 @@ nsapi_error_t InternetSocket::close()
_socket = 0;
ret = _stack->socket_close(socket);
_stack = 0; // Invalidate the stack pointer - otherwise open() fails.
_socket_stats.stats_update_socket_state(this, SOCK_CLOSED);
// Wakeup anything in a blocking operation
// on this socket
event();

View File

@ -26,6 +26,7 @@
#include "rtos/EventFlags.h"
#include "Callback.h"
#include "mbed_toolchain.h"
#include "SocketStats.h"
/** Socket implementation that uses IP network stack.
* Not to be directly used by applications. Cannot be directly instantiated.
@ -176,6 +177,7 @@ protected:
static const int FINISHED_FLAG = 0x3u;
friend class DTLSSocket; // Allow DTLSSocket::connect() to do name resolution on the _stack
SocketStats _socket_stats;
#endif //!defined(DOXYGEN_ONLY)
};

View File

@ -0,0 +1,160 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "SocketStats.h"
#include "platform/mbed_error.h"
#include "platform/mbed_assert.h"
#ifdef MBED_CONF_RTOS_PRESENT
#include "rtos/Kernel.h"
#endif
#include <string.h>
#include <stdlib.h>
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
SingletonPtr<PlatformMutex> SocketStats::_mutex;
mbed_stats_socket_t SocketStats::_stats[MBED_CONF_NSAPI_SOCKET_STATS_MAX_COUNT];
uint32_t SocketStats::_size = 0;
int SocketStats::get_entry_position(const Socket *const reference_id)
{
for (uint32_t j = 0; j < _size; j++) {
if (_stats[j].reference_id == reference_id) {
return j;
}
}
return -1;
}
#endif
size_t SocketStats::mbed_stats_socket_get_each(mbed_stats_socket_t *stats, size_t count)
{
MBED_ASSERT(stats != NULL);
size_t i = 0;
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
memset(stats, 0, count * sizeof(mbed_stats_socket_t));
_mutex->lock();
for (uint32_t j = 0; j < count; j++) {
if (_stats[j].reference_id) {
memcpy(&stats[i], &_stats[j], sizeof(mbed_stats_socket_t));
i++;
}
}
_mutex->unlock();
#endif
return i;
}
SocketStats::SocketStats()
{
}
void SocketStats::stats_new_socket_entry(const Socket *const reference_id)
{
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
_mutex->lock();
if (get_entry_position(reference_id) >= 0) {
// Duplicate entry
MBED_WARNING1(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STATS, MBED_ERROR_CODE_INVALID_INDEX), "Duplicate socket Reference ID ", reference_id);
} else if (_size < MBED_CONF_NSAPI_SOCKET_STATS_MAX_COUNT) {
// Add new entry
_stats[_size].reference_id = (Socket *)reference_id;
_size++;
} else {
int position = -1;
uint64_t oldest_time = 0;
// Determine which entry in the list shall be over-written
for (uint32_t j = 0; j < MBED_CONF_NSAPI_SOCKET_STATS_MAX_COUNT; j++) {
if (SOCK_CLOSED == _stats[j].state) {
if ((0 == oldest_time) || (oldest_time < _stats[j].last_change_tick)) {
oldest_time = _stats[j].last_change_tick;
position = j;
}
}
}
if (-1 == position) {
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STATS, MBED_ERROR_CODE_OUT_OF_RESOURCES), "List full with all open sockets");
}
memset(&_stats[position], 0, sizeof(mbed_stats_socket_t));
_stats[position].reference_id = (Socket *)reference_id;
}
_mutex->unlock();
#endif
return;
}
void SocketStats::stats_update_socket_state(const Socket *const reference_id, socket_state state)
{
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
_mutex->lock();
int position = get_entry_position(reference_id);
if (position >= 0) {
_stats[position].state = state;
#ifdef MBED_CONF_RTOS_PRESENT
_stats[position].last_change_tick = rtos::Kernel::get_ms_count();
#endif
}
_mutex->unlock();
#endif
}
void SocketStats::stats_update_peer(const Socket *const reference_id, const SocketAddress &peer)
{
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
_mutex->lock();
int position = get_entry_position(reference_id);
if ((position >= 0) && (!_stats[position].peer)) {
_stats[position].peer = peer;
}
_mutex->unlock();
#endif
}
void SocketStats::stats_update_proto(const Socket *const reference_id, nsapi_protocol_t proto)
{
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
_mutex->lock();
int position = get_entry_position(reference_id);
if (position >= 0) {
_stats[position].proto = proto;
}
_mutex->unlock();
#endif
}
void SocketStats::stats_update_sent_bytes(const Socket *const reference_id, size_t sent_bytes)
{
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
_mutex->lock();
int position = get_entry_position(reference_id);
if ((position >= 0) && ((int32_t)sent_bytes > 0)) {
_stats[position].sent_bytes += sent_bytes;
}
_mutex->unlock();
#endif
}
void SocketStats::stats_update_recv_bytes(const Socket *const reference_id, size_t recv_bytes)
{
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
_mutex->lock();
int position = get_entry_position(reference_id);
if ((position >= 0) && ((int32_t)recv_bytes > 0)) {
_stats[position].recv_bytes += recv_bytes;
}
_mutex->unlock();
#endif
}

View File

@ -0,0 +1,162 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOCKET_STATS_H
#define SOCKET_STATS_H
#include "platform/SingletonPtr.h"
#include "platform/PlatformMutex.h"
#include "netsocket/Socket.h"
#include "SocketAddress.h"
#include "hal/ticker_api.h"
#ifndef MBED_CONF_NSAPI_SOCKET_STATS_MAX_COUNT
#define MBED_CONF_NSAPI_SOCKET_STATS_MAX_COUNT 10
#endif
/** Enum of socket states
*
* Can be used to specify current state of socket - open, closed, connected or listen.
*
* @enum socket_state
*/
typedef enum {
SOCK_CLOSED, /**< Socket is closed and does not exist anymore in the system */
SOCK_OPEN, /**< Socket is open but not associated to any peer address */
SOCK_CONNECTED, /**< Socket is associated to peer address, either by connect() or sendto()/recvfrom() calls */
SOCK_LISTEN, /**< Socket is listening for incoming connections */
} socket_state;
/** Structure to parse socket statistics
*/
typedef struct {
Socket *reference_id; /**< Used for identifying socket */
SocketAddress peer; /**< Last associated peername of this socket (Destination address) */
socket_state state; /**< State of this socket */
nsapi_protocol_t proto; /**< Specifies a protocol used with socket */
size_t sent_bytes; /**< Data sent through this socket */
size_t recv_bytes; /**< Data received through this socket */
us_timestamp_t last_change_tick;/**< osKernelGetTick() when state last changed */
} mbed_stats_socket_t;
/** SocketStats class
*
* Class to get the network socket statistics
*/
class SocketStats {
public:
#if !defined(DOXYGEN_ONLY)
/** Create an socket statictics object
*
* Application users must not create class objects.
* Entities reporting network statistics create the class object.
* Application can fetch network statistics using static `mbed_stats_socket_get_each` API
* without creating an object.
*/
SocketStats();
virtual ~SocketStats()
{
}
#endif
/**
* Fill the passed array of structures with the socket statistics for each created socket.
*
* @param stats A pointer to an array of mbed_stats_socket_t structures to fill
* @param count The number of mbed_stats_socket_t structures in the provided array
* @return The number of mbed_stats_socket_t structures that have been filled.
* If the number of sockets on the system is less than or equal to count,
* it will equal the number of sockets created (active or closed).
* If the number of sockets on the system is greater than count,
* it will equal count.
*/
static size_t mbed_stats_socket_get_each(mbed_stats_socket_t *stats, size_t count);
#if !defined(DOXYGEN_ONLY)
/** Add entry of newly created socket in statistics array.
* API used by socket (TCP or UDP) layers only, not to be used by application.
*
* @param reference_id ID to identify socket in data array.
*
* @Note: The entry in the array is maintained even after the socket is closed.
* The entry is overwritten for sockets that were closed first, in case
* the socket creation count exceeds `MBED_CONF_NSAPI_SOCKET_STATS_MAX_COUNT`.
*
*/
void stats_new_socket_entry(const Socket *const reference_id);
/** Updates the state of the socket and records `tick_last_change`.
* API used by socket (TCP or UDP) layers only, not to be used by application.
*
* @param reference_id ID to identify socket in data array.
* @param state Parameter to update the current state of the socket.
*
*/
void stats_update_socket_state(const Socket *const reference_id, socket_state state);
/** Update the peer information of the socket.
* API used by socket (TCP or UDP) layers only, not to be used by application.
*
* @param reference_id ID to identify socket in data array.
* @param peer Parameter to update destination peer information.
*
*/
void stats_update_peer(const Socket *const reference_id, const SocketAddress &peer);
/** Update socket protocol.
* API used by socket (TCP or UDP) layers only, not to be used by application.
*
* @param reference_id ID to identify socket in data array.
* @param proto Parameter to update the protocol type of socket.
*
*/
void stats_update_proto(const Socket *const reference_id, nsapi_protocol_t proto);
/** Update bytes sent on socket, which is cumulative count per socket.
* API used by socket (TCP or UDP) layers only, not to be used by application.
*
* @param reference_id ID to identify socket in data array.
* @param sent_bytes Parameter to append bytes sent over the socket.
*
*/
void stats_update_sent_bytes(const Socket *const reference_id, size_t sent_bytes);
/** Update bytes received on socket, which is cumulative count per socket
* API used by socket (TCP or UDP) layers only, not to be used by application.
*
* @param reference_id ID to identify socket in data array.
* @param recv_bytes Parameter to append bytes the socket receives.
*
*/
void stats_update_recv_bytes(const Socket *const reference_id, size_t recv_bytes);
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
private:
static mbed_stats_socket_t _stats[MBED_CONF_NSAPI_SOCKET_STATS_MAX_COUNT];
static SingletonPtr<PlatformMutex> _mutex;
static uint32_t _size;
/** Internal function to scan the array and get the position of the element in the list.
*
* @param reference_id ID to identify the socket in the data array.
*
*/
int get_entry_position(const Socket *const reference_id);
#endif
#endif
};
#endif

View File

@ -20,6 +20,7 @@ using mbed::Callback;
TCPServer::TCPServer()
{
_socket_stats.stats_update_proto(this, NSAPI_TCP);
}
TCPServer::~TCPServer()
@ -52,7 +53,8 @@ nsapi_error_t TCPServer::accept(TCPSocket *connection, SocketAddress *address)
connection->_socket = socket;
connection->_event = Callback<void()>(connection, &TCPSocket::event);
_stack->socket_attach(socket, &Callback<void()>::thunk, &connection->_event);
_socket_stats.stats_update_peer(connection, *address);
_socket_stats.stats_update_socket_state(connection, SOCK_CONNECTED);
connection->_lock.unlock();
break;
} else if ((_timeout == 0) || (ret != NSAPI_ERROR_WOULD_BLOCK)) {

View File

@ -20,6 +20,7 @@
TCPSocket::TCPSocket()
{
_socket_stats.stats_update_proto(this, NSAPI_TCP);
}
TCPSocket::TCPSocket(TCPSocket *parent, nsapi_socket_t socket, SocketAddress address)
@ -28,7 +29,7 @@ TCPSocket::TCPSocket(TCPSocket *parent, nsapi_socket_t socket, SocketAddress add
_stack = parent->_stack;
_factory_allocated = true;
_remote_peer = address;
_socket_stats.stats_new_socket_entry(this);
_event = mbed::Callback<void()>(this, &TCPSocket::event);
_stack->socket_attach(socket, &mbed::Callback<void()>::thunk, &_event);
}
@ -64,6 +65,7 @@ nsapi_error_t TCPSocket::connect(const SocketAddress &address)
_pending = 0;
ret = _stack->socket_connect(_socket, address);
if ((_timeout == 0) || !(ret == NSAPI_ERROR_IN_PROGRESS || ret == NSAPI_ERROR_ALREADY)) {
_socket_stats.stats_update_socket_state(this, SOCK_CONNECTED);
break;
} else {
blocking_connect_in_progress = true;
@ -89,11 +91,13 @@ nsapi_error_t TCPSocket::connect(const SocketAddress &address)
/* Non-blocking connect gives "EISCONN" once done - convert to OK for blocking mode if we became connected during this call */
if (ret == NSAPI_ERROR_IS_CONNECTED && blocking_connect_in_progress) {
_socket_stats.stats_update_socket_state(this, SOCK_CONNECTED);
ret = NSAPI_ERROR_OK;
}
if (ret == NSAPI_ERROR_OK || ret == NSAPI_ERROR_IN_PROGRESS) {
_remote_peer = address;
_socket_stats.stats_update_peer(this, _remote_peer);
}
_lock.unlock();
@ -178,6 +182,7 @@ nsapi_size_or_error_t TCPSocket::send(const void *data, nsapi_size_t size)
} else if (written == 0) {
return NSAPI_ERROR_WOULD_BLOCK;
} else {
_socket_stats.stats_update_sent_bytes(this, written);
return written;
}
}
@ -208,6 +213,7 @@ nsapi_size_or_error_t TCPSocket::recv(void *data, nsapi_size_t size)
_pending = 0;
ret = _stack->socket_recv(_socket, data, size);
if ((_timeout == 0) || (ret != NSAPI_ERROR_WOULD_BLOCK)) {
_socket_stats.stats_update_recv_bytes(this, ret);
break;
} else {
uint32_t flag;
@ -252,6 +258,9 @@ nsapi_error_t TCPSocket::listen(int backlog)
ret = NSAPI_ERROR_NO_SOCKET;
} else {
ret = _stack->socket_listen(_socket, backlog);
if (NSAPI_ERROR_OK == ret) {
_socket_stats.stats_update_socket_state(this, SOCK_LISTEN);
}
}
_lock.unlock();

View File

@ -20,6 +20,7 @@
UDPSocket::UDPSocket()
{
_socket_stats.stats_update_proto(this, NSAPI_UDP);
}
UDPSocket::~UDPSocket()
@ -34,6 +35,8 @@ nsapi_protocol_t UDPSocket::get_proto()
nsapi_error_t UDPSocket::connect(const SocketAddress &address)
{
_remote_peer = address;
_socket_stats.stats_update_peer(this, _remote_peer);
_socket_stats.stats_update_socket_state(this, SOCK_CONNECTED);
return NSAPI_ERROR_OK;
}
@ -57,7 +60,10 @@ nsapi_size_or_error_t UDPSocket::sendto(const SocketAddress &address, const void
nsapi_size_or_error_t ret;
_writers++;
if (_socket) {
_socket_stats.stats_update_socket_state(this, SOCK_OPEN);
_socket_stats.stats_update_peer(this, address);
}
while (true) {
if (!_socket) {
ret = NSAPI_ERROR_NO_SOCKET;
@ -67,6 +73,7 @@ nsapi_size_or_error_t UDPSocket::sendto(const SocketAddress &address, const void
_pending = 0;
nsapi_size_or_error_t sent = _stack->socket_sendto(_socket, address, data, size);
if ((0 == _timeout) || (NSAPI_ERROR_WOULD_BLOCK != sent)) {
_socket_stats.stats_update_sent_bytes(this, sent);
ret = sent;
break;
} else {
@ -114,6 +121,9 @@ nsapi_size_or_error_t UDPSocket::recvfrom(SocketAddress *address, void *buffer,
_readers++;
if (_socket) {
_socket_stats.stats_update_socket_state(this, SOCK_OPEN);
}
while (true) {
if (!_socket) {
ret = NSAPI_ERROR_NO_SOCKET;
@ -128,9 +138,11 @@ nsapi_size_or_error_t UDPSocket::recvfrom(SocketAddress *address, void *buffer,
continue;
}
_socket_stats.stats_update_peer(this, _remote_peer);
// Non-blocking sockets always return. Blocking only returns when success or errors other than WOULD_BLOCK
if ((0 == _timeout) || (NSAPI_ERROR_WOULD_BLOCK != recv)) {
ret = recv;
_socket_stats.stats_update_recv_bytes(this, recv);
break;
} else {
uint32_t flag;

View File

@ -30,6 +30,14 @@
"dns-cache-size": {
"help": "Number of cached host name resolutions",
"value": 3
},
"socket-stats-enable": {
"help": "Enable network socket statistics",
"value": false
},
"socket-stats-max-count": {
"help": "Maximum number of socket statistics cached",
"value": 10
}
},
"target_overrides": {

View File

@ -23,6 +23,7 @@
#ifndef SINGLETONPTR_H
#define SINGLETONPTR_H
#include <stdlib.h>
#include <stdint.h>
#include <new>
#include "platform/mbed_assert.h"

View File

@ -254,6 +254,7 @@ typedef enum _mbed_error_type_t {
MBED_MODULE_DRIVER_USB 21 USB Driver
MBED_MODULE_TARGET_SDK 22 SDK
MBED_MODULE_BLE 23 BLE
MBED_MODULE_NETWORK_STATS 24 Network Statistics
MBED_MODULE_UNKNOWN 255 Unknown module
\endverbatim
@ -284,6 +285,7 @@ typedef enum _mbed_module_type {
MBED_MODULE_DRIVER_USB,
MBED_MODULE_TARGET_SDK,
MBED_MODULE_BLE,
MBED_MODULE_NETWORK_STATS,
/* Add More entities here as required */
MBED_MODULE_UNKNOWN = 255,

View File

@ -1,33 +1,41 @@
{
"UBLOX_EVK_ODIN_W2": {
"nsapi.socket-stats-enable": true,
"default_test_configuration": "NONE",
"test_configurations": ["HEAPBLOCKDEVICE_AND_WIFI", "HEAPBLOCKDEVICE_AND_ETHERNET"]
},
"REALTEK_RTL8195AM": {
"nsapi.socket-stats-enable": true,
"default_test_configuration": "NONE",
"test_configurations": ["HEAPBLOCKDEVICE_AND_WIFI"]
},
"K64F": {
"nsapi.socket-stats-enable": true,
"default_test_configuration": "HEAPBLOCKDEVICE_AND_ETHERNET",
"test_configurations": ["HEAPBLOCKDEVICE_AND_ETHERNET", "NANOSTACK_MAC_TESTER", "ESP8266_WIFI", "ETHERNET"]
},
"NUCLEO_F429ZI": {
"nsapi.socket-stats-enable": true,
"default_test_configuration": "HEAPBLOCKDEVICE_AND_ETHERNET",
"test_configurations": ["HEAPBLOCKDEVICE_AND_ETHERNET", "NANOSTACK_MAC_TESTER"]
},
"DISCO_L475VG_IOT01A": {
"nsapi.socket-stats-enable": true,
"default_test_configuration": "NONE",
"test_configurations": ["ISM43362_WIFI"]
},
"DISCO_F413ZH": {
"nsapi.socket-stats-enable": true,
"default_test_configuration": "NONE",
"test_configurations": ["ISM43362_WIFI"]
},
"MTB_UBLOX_ODIN_W2": {
"nsapi.socket-stats-enable": true,
"default_test_configuration": "NONE",
"test_configurations": ["HEAPBLOCKDEVICE_AND_WIFI"]
},
"MTB_ADV_WISE_1530": {
"nsapi.socket-stats-enable": true,
"default_test_configuration": "NONE",
"test_configurations": ["HEAPBLOCKDEVICE_AND_WIFI"]
},