Skip to content

Commit 77f268e

Browse files
author
Arto Kinnunen
committed
Add getsockopt option to read network property
Add getsockopt options NSAPI_LATENCY and NSAPI_STAGGER to read network specific timing constraints from socket. -NS_LATENCY returns estimated latency to given address. -NSAPI_STAGGER returns estimated initial delay that application should wait before transmitting data to network. Application can use the new options to avoid network congestion by adjusting transmission delays and retry timeouts. Add wrappers to make API usage easier: -get_rtt_estimate_to_address -get_stagger_estimate_to_address This is backport of the #12522
1 parent b6370b4 commit 77f268e

File tree

5 files changed

+150
-2
lines changed

5 files changed

+150
-2
lines changed

UNITTESTS/features/netsocket/InternetSocket/test_InternetSocket.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,18 @@ TEST_F(TestInternetSocket, modify_multicast_group)
185185
EXPECT_EQ(socket->leave_multicast_group(a), NSAPI_ERROR_UNSUPPORTED);
186186
}
187187

188+
TEST_F(TestInternetSocket, network_property)
189+
{
190+
SocketAddress a("fd00:db8::ff", 1024);
191+
uint32_t rtt_estimate;
192+
uint16_t stagger_min, stagger_max, stagger_rand;
193+
stack.return_value = NSAPI_ERROR_OK;
194+
socket->open(&stack);
195+
EXPECT_EQ(socket->get_rtt_estimate_to_address(a, &rtt_estimate), NSAPI_ERROR_UNSUPPORTED);
196+
EXPECT_EQ(socket->get_rtt_estimate_to_address(a, NULL), NSAPI_ERROR_PARAMETER);
197+
EXPECT_EQ(socket->get_stagger_estimate_to_address(a, 1, &stagger_min, &stagger_max, &stagger_rand), NSAPI_ERROR_UNSUPPORTED);
198+
}
199+
188200
// set_blocking and set_timeout are tested within TCPSocket.
189201

190202
TEST_F(TestInternetSocket, bind_no_socket)

features/nanostack/nanostack-interface/Nanostack.cpp

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -840,18 +840,58 @@ nsapi_error_t Nanostack::setsockopt(void *handle, int level, int optname, const
840840
nsapi_error_t Nanostack::getsockopt(void *handle, int level, int optname, void *optval, unsigned *optlen)
841841
{
842842
NanostackSocket *socket = static_cast<NanostackSocket *>(handle);
843+
843844
if (handle == NULL) {
844845
MBED_ASSERT(false);
845846
return NSAPI_ERROR_NO_SOCKET;
846847
}
847848

848849
NanostackLockGuard lock;
850+
// pointers to Mbed OS structures
851+
nsapi_latency_req_t *ns_latency_r = static_cast<nsapi_latency_req_t *>(optval);
852+
nsapi_stagger_req_t *ns_stagger_r = static_cast<nsapi_stagger_req_t *>(optval);
853+
// Nanostack internal structures
854+
ns_ipv6_latency_t nanostack_latency;
855+
ns_ipv6_stagger_t nanostack_stagger;
856+
int nanostack_optname = optname;
857+
858+
void *ns_option_value = optval;
859+
860+
if (level == NSAPI_SOCKET) {
861+
if (optname == NSAPI_LATENCY) {
862+
if (*optlen < sizeof(nsapi_latency_req_t)) {
863+
return NSAPI_ERROR_PARAMETER;
864+
}
865+
// Adjust to Nanostack namespace
866+
level = SOCKET_IPPROTO_IPV6;
867+
nanostack_optname = SOCKET_LATENCY;
868+
memcpy(nanostack_latency.dest_addr, ns_latency_r->addr, 16);
869+
ns_option_value = &nanostack_latency;
870+
} else if (optname == NSAPI_STAGGER) {
871+
if (*optlen < sizeof(nsapi_stagger_req_t)) {
872+
return NSAPI_ERROR_PARAMETER;
873+
}
874+
// Adjust to Nanostack namespace
875+
level = SOCKET_IPPROTO_IPV6;
876+
nanostack_optname = SOCKET_STAGGER;
877+
memcpy(nanostack_stagger.dest_addr, ns_stagger_r->addr, 16);
878+
nanostack_stagger.data_amount = ns_stagger_r->data_amount;
879+
ns_option_value = &nanostack_stagger;
880+
}
881+
}
849882

850883
uint16_t optlen16 = *optlen;
851884

852-
int retcode = ::socket_getsockopt(socket->socket_id, level, optname, optval, &optlen16);
885+
int retcode = ::socket_getsockopt(socket->socket_id, level, nanostack_optname, ns_option_value, &optlen16);
853886
if (retcode == 0) {
854887
*optlen = optlen16;
888+
if (optname == NSAPI_LATENCY) {
889+
ns_latency_r->latency = nanostack_latency.latency;
890+
} else if (optname == NSAPI_STAGGER) {
891+
ns_stagger_r->stagger_min = nanostack_stagger.stagger_min;
892+
ns_stagger_r->stagger_max = nanostack_stagger.stagger_max;
893+
ns_stagger_r->stagger_rand = nanostack_stagger.stagger_rand;
894+
}
855895
return NSAPI_ERROR_OK;
856896
} else if (retcode == -2) {
857897
return NSAPI_ERROR_UNSUPPORTED;

features/netsocket/InternetSocket.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,54 @@ int InternetSocket::leave_multicast_group(const SocketAddress &address)
119119
return modify_multicast_group(address, NSAPI_DROP_MEMBERSHIP);
120120
}
121121

122+
int InternetSocket::get_rtt_estimate_to_address(const SocketAddress &address, uint32_t *rtt_estimate)
123+
{
124+
nsapi_error_t ret;
125+
nsapi_latency_req_t ns_api_latency_req;
126+
unsigned opt_len = sizeof(nsapi_latency_req_t);
127+
128+
if (!rtt_estimate) {
129+
return NSAPI_ERROR_PARAMETER;
130+
}
131+
132+
// Set up address
133+
memcpy(ns_api_latency_req.addr, address.get_ip_bytes(), 16);
134+
135+
ret = this->getsockopt(NSAPI_SOCKET, NSAPI_LATENCY, &ns_api_latency_req, &opt_len);
136+
if (ret == NSAPI_ERROR_OK) {
137+
// success, latency found. Convert to RTT.
138+
*rtt_estimate = ns_api_latency_req.latency * 2;
139+
}
140+
141+
return ret;
142+
}
143+
144+
int InternetSocket::get_stagger_estimate_to_address(const SocketAddress &address, uint16_t data_amount, uint16_t *stagger_min, uint16_t *stagger_max, uint16_t *stagger_rand)
145+
{
146+
nsapi_error_t ret;
147+
nsapi_stagger_req_t nsapi_stagger;
148+
unsigned opt_len = sizeof(nsapi_stagger_req_t);
149+
150+
// Set up address
151+
memcpy(nsapi_stagger.addr, address.get_ip_bytes(), 16);
152+
nsapi_stagger.data_amount = data_amount;
153+
154+
ret = this->getsockopt(NSAPI_SOCKET, NSAPI_STAGGER, &nsapi_stagger, &opt_len);
155+
if (ret == NSAPI_ERROR_OK) {
156+
// success, stagger found
157+
if (stagger_min) {
158+
*stagger_min = nsapi_stagger.stagger_min;
159+
}
160+
if (stagger_max) {
161+
*stagger_max = nsapi_stagger.stagger_max;
162+
}
163+
if (stagger_rand) {
164+
*stagger_rand = nsapi_stagger.stagger_rand;
165+
}
166+
}
167+
168+
return ret;
169+
}
122170

123171
nsapi_error_t InternetSocket::bind(uint16_t port)
124172
{

features/netsocket/InternetSocket.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,35 @@ class InternetSocket : public Socket {
8686
*/
8787
int leave_multicast_group(const SocketAddress &address);
8888

89+
/** Get estimated round trip time to destination address.
90+
*
91+
* Use estimated round trip time to adjust application retry timers to work in networks
92+
* that have low data rate and high latency.
93+
*
94+
* @param address Destination address to use in rtt estimate.
95+
* @param rtt_estimate Returned round trip time value in milliseconds.
96+
* @return NSAPI_ERROR_OK on success.
97+
* @return NSAPI_ERROR_PARAMETER if the provided pointer is invalid.
98+
* @return negative error code on other failures (@see InternetSocket::getsockopt).
99+
*/
100+
int get_rtt_estimate_to_address(const SocketAddress &address, uint32_t *rtt_estimate);
101+
102+
/** Get estimated stagger value.
103+
*
104+
* Stagger value is a time that application should wait before using heavy network operations after connecting to network.
105+
* Purpose of staggering is to avoid network congestion that may happen in low bandwith networks if multiple
106+
* applications simultaneously start heavy network usage after joining to the network.
107+
*
108+
* @param address Destination added used to estimate stagger value.
109+
* @param data_amount Amount of bytes to transfer in kilobytes.
110+
* @param stagger_min Minimum stagger value in seconds.
111+
* @param stagger_max Maximum stagger value in seconds.
112+
* @param stagger_rand Randomized stagger value between stagger_min and stagger_max in seconds.
113+
* @return NSAPI_ERROR_OK on success.
114+
* @return negative error code on other failures (@see InternetSocket::getsockopt).
115+
*/
116+
int get_stagger_estimate_to_address(const SocketAddress &address, uint16_t data_amount, uint16_t *stagger_min, uint16_t *stagger_max, uint16_t *stagger_rand);
117+
89118
/** Bind the socket to a port on which to receive data.
90119
*
91120
* @param port Local port to bind.

features/netsocket/nsapi_types.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,9 @@ typedef enum nsapi_socket_option {
267267
NSAPI_RCVBUF, /*!< Sets recv buffer size */
268268
NSAPI_ADD_MEMBERSHIP, /*!< Add membership to multicast address */
269269
NSAPI_DROP_MEMBERSHIP, /*!< Drop membership to multicast address */
270-
NSAPI_BIND_TO_DEVICE, /*!< Bind socket network interface name*/
270+
NSAPI_BIND_TO_DEVICE, /*!< Bind socket network interface name*/
271+
NSAPI_LATENCY, /*!< Read estimated latency to destination */
272+
NSAPI_STAGGER, /*!< Read estimated stagger value to destination */
271273
} nsapi_socket_option_t;
272274

273275
typedef enum nsapi_tlssocket_level {
@@ -338,6 +340,23 @@ typedef struct nsapi_ip_mreq {
338340
nsapi_addr_t imr_interface; /* local IP address of interface */
339341
} nsapi_ip_mreq_t;
340342

343+
/** nsapi_latency_req structure
344+
*/
345+
typedef struct nsapi_latency_req {
346+
uint8_t addr[16]; /* [IN] Destination address to estimate latency */
347+
uint32_t latency; /* [OUT] Latency value */
348+
} nsapi_latency_req_t;
349+
350+
/** nsapi_stagger_req structure
351+
*/
352+
typedef struct nsapi_stagger_req {
353+
uint8_t addr[16]; /* [IN] Destination address to estimate stagger */
354+
uint16_t data_amount; /* [IN] Amount of data to be sent in kilobytes */
355+
uint16_t stagger_min; /* [OUT] Minimum stagger value in seconds */
356+
uint16_t stagger_max; /* [OUT] Maximum stagger value in seconds */
357+
uint16_t stagger_rand; /* [OUT] Randomized stagger value in seconds */
358+
} nsapi_stagger_req_t;
359+
341360
/** nsapi_stack_api structure
342361
*
343362
* Common api structure for network stack operations. A network stack

0 commit comments

Comments
 (0)