Add getsockopt option to reading 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.
pull/12522/head
Arto Kinnunen 2020-02-25 15:25:17 +02:00
parent 7b0c38aabb
commit a7d3a981b7
4 changed files with 118 additions and 2 deletions

View File

@ -838,18 +838,58 @@ nsapi_error_t Nanostack::setsockopt(void *handle, int level, int optname, const
nsapi_error_t Nanostack::getsockopt(void *handle, int level, int optname, void *optval, unsigned *optlen)
{
NanostackSocket *socket = static_cast<NanostackSocket *>(handle);
if (handle == NULL) {
MBED_ASSERT(false);
return NSAPI_ERROR_NO_SOCKET;
}
NanostackLockGuard lock;
// pointers to Mbed OS structures
nsapi_latency_req_t *ns_latency_r = static_cast<nsapi_latency_req_t *>(optval);
nsapi_stagger_req_t *ns_stagger_r = static_cast<nsapi_stagger_req_t *>(optval);
// Nanostack internal structures
ns_ipv6_latency_t nanostack_latency;
ns_ipv6_stagger_t nanostack_stagger;
int nanostack_optname = optname;
void *ns_option_value = optval;
if (level == NSAPI_SOCKET) {
if (optname == NSAPI_LATENCY) {
if (*optlen < sizeof(nsapi_latency_req_t)) {
return NSAPI_ERROR_PARAMETER;
}
// Adjust to Nanostack namespace
level = SOCKET_IPPROTO_IPV6;
nanostack_optname = SOCKET_LATENCY;
memcpy(nanostack_latency.dest_addr, ns_latency_r->addr, 16);
ns_option_value = &nanostack_latency;
} else if (optname == NSAPI_STAGGER) {
if (*optlen < sizeof(nsapi_stagger_req_t)) {
return NSAPI_ERROR_PARAMETER;
}
// Adjust to Nanostack namespace
level = SOCKET_IPPROTO_IPV6;
nanostack_optname = SOCKET_STAGGER;
memcpy(nanostack_stagger.dest_addr, ns_stagger_r->addr, 16);
nanostack_stagger.data_amount = ns_stagger_r->data_amount;
ns_option_value = &nanostack_stagger;
}
}
uint16_t optlen16 = *optlen;
int retcode = ::socket_getsockopt(socket->socket_id, level, optname, optval, &optlen16);
int retcode = ::socket_getsockopt(socket->socket_id, level, nanostack_optname, ns_option_value, &optlen16);
if (retcode == 0) {
*optlen = optlen16;
if (optname == NSAPI_LATENCY) {
ns_latency_r->latency = nanostack_latency.latency;
} else if (optname == NSAPI_STAGGER) {
ns_stagger_r->stagger_min = nanostack_stagger.stagger_min;
ns_stagger_r->stagger_max = nanostack_stagger.stagger_max;
ns_stagger_r->stagger_rand = nanostack_stagger.stagger_rand;
}
return NSAPI_ERROR_OK;
} else if (retcode == -2) {
return NSAPI_ERROR_UNSUPPORTED;

View File

@ -114,6 +114,44 @@ int InternetSocket::leave_multicast_group(const SocketAddress &address)
return modify_multicast_group(address, NSAPI_DROP_MEMBERSHIP);
}
int InternetSocket::get_latency_estimate_to_address(const SocketAddress &address, uint32_t *latency)
{
nsapi_error_t ret;
nsapi_latency_req_t ns_api_latency_req;
unsigned opt_len = sizeof(nsapi_latency_req_t);
// Set up address
memcpy(ns_api_latency_req.addr, address.get_ip_bytes(), 16);
ret = this->getsockopt(NSAPI_SOCKET, NSAPI_LATENCY, (void *)&ns_api_latency_req, &opt_len);
if (ret == NSAPI_ERROR_OK) {
// success, latency found
*latency = ns_api_latency_req.latency;
}
return ret;
}
int InternetSocket::get_stagger_estimate_to_address(const SocketAddress &address, uint32_t data_amount, uint16_t *stagger_min, uint16_t *stagger_max, uint16_t *stagger_rand)
{
nsapi_error_t ret;
nsapi_stagger_req_t nsapi_stagger;
unsigned opt_len = sizeof(nsapi_stagger_req_t);
// Set up address
memcpy(nsapi_stagger.addr, address.get_ip_bytes(), 16);
nsapi_stagger.data_amount = data_amount;
ret = this->getsockopt(NSAPI_SOCKET, NSAPI_STAGGER, (void *)&nsapi_stagger, &opt_len);
if (ret == NSAPI_ERROR_OK) {
// success, stagger found
*stagger_min = nsapi_stagger.stagger_min;
*stagger_max = nsapi_stagger.stagger_max;
*stagger_rand = nsapi_stagger.stagger_rand;
}
return ret;
}
nsapi_error_t InternetSocket::bind(uint16_t port)
{

View File

@ -86,6 +86,25 @@ public:
*/
int leave_multicast_group(const SocketAddress &address);
/** Get estimated latency to reach destination address.
*
* @param address Destination address to estimate latency.
* @param latency Returned latency value in milliseconds.
* @return NSAPI_ERROR_OK on success, negative error code on failure (@see InternetSocket::getsockopt).
*/
int get_latency_estimate_to_address(const SocketAddress &address, uint32_t *latency);
/** Get estimated stagger value to reach destination address.
*
* @param address Address to estimate stagger values.
* @param data_amount Amount of bytes to transfer in kilobytes.
* @param stagger_min Minimum stagger value in seconds.
* @param stagger_max Maximum stagger value in seconds.
* @param stagger_rand Randomized stagger value in seconds.
* @return NSAPI_ERROR_OK on success, negative error code on failure (@see InternetSocket::getsockopt).
*/
int get_stagger_estimate_to_address(const SocketAddress &address, uint32_t data_amount, uint16_t *stagger_min, uint16_t *stagger_max, uint16_t *stagger_rand);
/** Bind the socket to a port on which to receive data.
*
* @param port Local port to bind.

View File

@ -269,7 +269,9 @@ typedef enum nsapi_socket_option {
NSAPI_RCVBUF, /*!< Sets recv buffer size */
NSAPI_ADD_MEMBERSHIP, /*!< Add membership to multicast address */
NSAPI_DROP_MEMBERSHIP, /*!< Drop membership to multicast address */
NSAPI_BIND_TO_DEVICE, /*!< Bind socket network interface name*/
NSAPI_BIND_TO_DEVICE, /*!< Bind socket network interface name*/
NSAPI_LATENCY, /*!< Read estimated latency to destination */
NSAPI_STAGGER, /*!< Read estimated stagger value to destination */
} nsapi_socket_option_t;
typedef enum nsapi_tlssocket_level {
@ -340,6 +342,23 @@ typedef struct nsapi_ip_mreq {
nsapi_addr_t imr_interface; /* local IP address of interface */
} nsapi_ip_mreq_t;
/** nsapi_latency_req structure
*/
typedef struct nsapi_latency_req {
uint8_t addr[16]; /* [IN] Destination address to estimate latency */
uint32_t latency; /* [OUT] Latency value */
} nsapi_latency_req_t;
/** nsapi_stagger_req structure
*/
typedef struct nsapi_stagger_req {
uint8_t addr[16]; /* [IN] Destination address to estimate stagger */
uint16_t data_amount; /* [IN] Amount of data to be sent in kilobytes */
uint16_t stagger_min; /* [OUT] Minimum stagger value in seconds */
uint16_t stagger_max; /* [OUT] Maximum stagger value in seconds */
uint16_t stagger_rand; /* [OUT] Randomized stagger value in seconds */
} nsapi_stagger_req_t;
/** nsapi_stack_api structure
*
* Common api structure for network stack operations. A network stack